Changelog
Source:
en/reference/changelog.md· Live: https://docs.1pass.dev/en/reference/changelog LLM-sanitized: internal links absolutized, VitePress containers → admonitions, line numbers in the Jump-to Index reference this rendered file (1-indexed).
📍 Jump-to Index
- L33-L41: ## 2026-08-12 — Native app-to-app handoff moves to
open.1pass.dev(Swift SDK v1.3.0) - L42-L50: ## 2026-07-08 — SDK Swift v1.1.0 — device PAK exchange, refresh verification, revoke/disconnect primitives
- L51-L59: ## 2026-07-02 — SDK v1.0.1 security hardening (at_hash + JWKS kty)
- L60-L71: ## 2026-06-24 — Passkey Phase 1–3
- L72-L98: ## 2026-05-28 — RP registration hurdles (Phase 2–5e) + Agent Quickstart
- L76-L81: ### Docs / agent surface
- L82-L91: ### RP registration hurdles (server-side, autoDeploy=off, manual deploy)
- L92-L94: ### Migration
- L95-L98: ### Tests
- L99-L131: ## 2026-05-15
- L110-L120: ### 2026-05-11 — Added
target_session_tokenPoP - L121-L131: ### 2026-05-11 — canonical resolution applied to the Easy Bracket RP
- L110-L120: ### 2026-05-11 — Added
- L132-L161: ## 2026-04-27 — Security review wave (Phase 1-14)
- L137-L140: ### Critical
- L141-L148: ### High
- L149-L154: ### Medium
- L155-L161: ### Summary of SDK user impact
- L162-L178: ## v0.1-alpha (2026-04-22 sync)
- L179-L185: ## Known limitations
- L186-L192: ## Roadmap (β)
Changelog
2026-08-12 — Native app-to-app handoff moves to open.1pass.dev (Swift SDK v1.3.0)
The /oauth/authorize Universal Link claim on api.1pass.dev exists for native app-to-app SSO, but it had the side effect of intercepting web RPs' browser OAuth flows on the same URL — a login started in Chrome would get grabbed by the logi app and the callback would land in a different browser, failing with state mismatch. We split the URL space onto a dedicated bouncer host to fix this structurally.
- Swift SDK v1.3.0 — the first-try app-to-app open now targets
open.1pass.dev/oauth/authorize, while theASWebAuthenticationSessionfallback keeps loadingapi.1pass.dev. Additive — existing integrations need nothing beyond a version bump.issuer, token exchange, and JWKS stay bound toapi(moving them would break token exchange, so the SDK splits only the authorize handoff leg). Staging/self-hosted issuers are never derived onto the bouncer — the SDK keeps the issuer host as-is, withnativeAuthorizeHostavailable for explicit override. The BFF primitiveauthorize(startURL:)(backend-assembled URLs) also ships in this tag; the host split does not apply to it (the backend stays authoritative). open.1pass.dev/oauth/authorizelanding page — if the Universal Link does not fire, a static landing page is shown (deliberately no auto-redirect — a redirect re-triggers the Universal Link in Safari) and the user taps through to the consent screen onapi. The query string is forwarded byte-for-byte — this also fixes the existing/authbouncer defect that dropped non-whitelisted parameters (login_hint,ui_locales, …) and re-encoded+.- AASA cleanup — removed dead claims that opened the app with nothing to show (
/oauth/callback*,/auth/callback*,/activate/*,/qr/pair/*, and more). No live deep link is affected. - Transition — both hosts currently keep their claims, so nothing breaks for existing integrations. Removing the
apiclaim (fully freeing the web flow) will be announced separately once older app builds have cycled through store updates. Manual-integration migration guidance: iOS (Swift) and Universal Links.
2026-07-08 — SDK Swift v1.1.0 — device PAK exchange, refresh verification, revoke/disconnect primitives
The Swift SDK now absorbs three backend auth calls that RPs used to hand-roll. All changes are additive (existing symbol signatures unchanged) — existing v1.0.x integrations keep working with no code change, and the new surface is opt-in.
LogiAuth.verify(_:)— verifies the id_token fromLogiAuthStorage.refresh()'sLogiAuthResultusing the same JWKS cache and RS256 verification assignIn(), promoting it to a verifiedLogiSession. Trusting a refreshed token'ssub/emailwithout verification reopens, on the refresh path, the signature gap thatsignIncloses — always route cold-launch session restore throughverify. (A refresh response carries no nonce, so nonce is not checked;at_hashis present-only.)LogiDeviceKey(LogiAuthStoragemodule, actor) — exchanges the OAuth JWT for a device-bound PAK (logi_pak_...) viaPOST /api/v1/me/device_keys/exchange. The/api/v1/*endpoints require a PAK, not the JWT, so RPs that need this exchange now use the SDK instead of a hand-rolled copy. It persistsdevice_uuid/device_secretidempotently to the Keychain and coalesces concurrent calls. When migrating an existing install, inject the legacykeychainServiceto preserve the stored credential (otherwise the server mints a fresh orphan DeviceCredential, with the 10/h exchange rate-limit and409 device_claimed_by_other_userrisk).LogiAuthStorage.revokeRefreshToken()/disconnectApp(pak:)— backchannel primitives.revokeRefreshToken()invalidates the stored refresh_token server-side (RFC 7009; a public client sendsclient_idonly; best-effort).disconnectApp(pak:)disconnects the RP viaDELETE /api/v1/me/connected_apps/{client_id}(Bearer=PAK,profile:write) and returnstrueonly on 2xx or 404,falseon 401/403/5xx/timeout — so the caller can preserve local credentials and retry (preserving account deletion's "server success → local wipe" invariant).signOut()remains a local-only wipe; its contract is unchanged.- Integration guide: iOS (Swift). SPM
from: "1.1.0", tagv1.1.0. All existing v1.0.1 golden vectors pass (non-breaking).
2026-07-02 — SDK v1.0.1 security hardening (at_hash + JWKS kty)
Non-breaking security hardening applied across all 7 SDKs (swift · android · browser · node · flutter · ruby · python).
- at_hash binding — the id_token's
at_hashclaim (base64url_nopad(SHA256(access_token UTF-8 bytes)[first 16 bytes]), OIDC §3.1.3.6) is verified against the access_token (present-only). Code-exchange SDKs wire the access_token internally to confirm the access_token↔id_token binding before returning the session; standalone verification can pass it via anaccessTokenargument. Rejected withat_hash_mismatch. - JWKS kty filter — signing-key selection now filters
kty=="RSA"+use∈{null,sig}+alg∈{null,RS256}before the kid match, so an EC (or other) key mixed into the JWKS still resolves the correct RSA signing key — robust to future key-type expansion. See the JWKS reference. - Swift — fail-closed CSPRNG (
SecRandomCopyBytes) + duplicate OAuth callback parameter guard. Android — re-verify the rotated id_token before persisting on refresh. - Published: npm
@logi-auth/browser@1.0.1·@logi-auth/server@1.0.1, gemlogi_auth 1.0.1, pub.devlogi_auth 1.0.1, SPM · JitPackv1.0.1tags. All existing v1.0.0 golden vectors still pass (non-breaking).
2026-06-24 — Passkey Phase 1–3
Server behavior for passkey login and approval flows that external RPs need to understand.
- WebAuthn L3 metadata storage — stores
backup_eligible,backup_state,backup_state_changed_at, andaaguidper passkey. RPs can inspect sync eligibility and AAGUID throughpasskeys:readresponses. sign_countanomaly WORM audit — when the authenticator counter goes backward, authentication is not failed solely for that signal, but an append-only audit event is written toAuthenticationAuditLog.- Web Conditional UI login — adds a passkey login path based on
/api/v1/passkeys/authentication_optionsand/api/v1/passkeys/authenticate. When the user selects a passkey in the browser Conditional UI, logi creates the web session. - App-approval passkey step-up — users with
approval_mode=passkeyapprove push approval requests with a UV-bearing passkey assertion. The challenge is bound to thePushApprovalRequestto prevent reuse. - Unauthenticated passkey rate limits — documents the unauthenticated limits that RPs adding their own passkey login UI need to know.
POST /api/v1/passkeys/authentication_optionsis capped at 20/min/IP, andPOST /api/v1/passkeys/authenticateis capped at 15/min/IP + 30/min/credential. See Rate Limits for the exact values. - Last-passkey deletion lockout prevention — blocks deleting the last active passkey while passkey-only approval mode is enabled, so the user does not lose their approval path.
- Authenticate hardening / throttle parity — prevents malformed credential JSON from surfacing as a 500, and aligns the per-credential throttle with JSON body parse/rewind handling.
2026-05-28 — RP registration hurdles (Phase 2–5e) + Agent Quickstart
Prevents AI agents from mass-producing RPs (Relying Parties) through automation, plus a docs cleanup around a single entry point.
Docs / agent surface
- New Agent Quickstart — /guide/agent-quickstart (Korean, 308 lines) + .en (English mirror). An 8-step execution order + automatic track detection + the F1–F8 pitfalls + a self-verify checklist. The
## ⭐ Agents start heresection at the top ofllms.txtexposes this page as the single entry point. - Webhook signature templates — templates/webhook (rails.rb / express.ts / nextjs-route.ts). Dual signature format + 5-minute replay window + timing-safe compare are baked in. Blocks the
// TODO: verify signatureanti-pattern. - "📋 Copy for LLM" button — top-right of every docs page. Copies the current page's
.mdmirror to the clipboard + a 2-second toast. Localized, dark-mode-aware, and mobile-friendly. @1pass/mcpv0.2.0 — adds 3 read-only docs tools (fetch_quickstart/get_doc/list_docs). No auth required. Fetch logi docs in natural language from Claude Desktop, Cursor, and Codex.
RP registration hurdles (server-side, autoDeploy=off, manual deploy)
- identity_verified_level gate — an
unverifieddeveloper is blocked from registering an RP. The JSON response includesverify_url. The console page shows a permanent banner + an "✉️ Send verification email" CTA (Phase 5c). created_viachannel recording —web | cli | mcp | api | rake. Self-identified via theX-Logi-Client-Typeheader. Permanently recorded in the audit log.- Automated risk assessment (
creation_risk_flagsjsonb) —wildcard_redirect_uri/sensitive_scope/unlisted_scope/high_volume_developer(≥5 in 7 days) /new_developer_account(within 7 days of signup) /suspicious_app_name(placeholder regex). These flags are evaluated at registration time and permanently recorded in the database. - Race-safe high-volume count —
Current.user.with_lock { evaluate + save }serializes concurrent registrations. Even with 5 firing at once, exactly 1 passes. - Rack::Attack throttle — POST
/developer/applicationsat 10/h + 30/d per developer session. POST/api/v1/applicationshas the same cap per PAK token (blocking CLI/MCP/automated mass production). Applied alongside the globalapi/ip60/min for defense in depth. - High-risk approval ack gate — when
wildcard_redirect_uriorsensitive_scopeappears alone, or 2+ flags accumulate, an admin can't approve without an explicitrisk_acknowledged: true. The web console replaces the button with "⚠ Approve despite known risk," and a Turbo confirm dialog shows the flag list. The iOS admin API (/api/v1/admin/applications/:id/approve) returns HTTP 409risk_acknowledgement_requiredwhen it's missing.ApplicationSubmission#approve!+auto_approve_during_betashare the same gate. - AdminAlertMailer high-risk alert — when
creation_risk_flagsis non-empty, the mailer runsdeliver_later. A 30-minute per-developer cooldown (Rails.cache) + a rescue on enqueue failure. Recipients are configured via theRP_HIGH_RISK_ALERT_TOenv (operator-only). - Stronger admin queue UI — each app row shows a risk badge + the
created_vialabel. A "⚠ Has risk signals" quick filter. At the top, a risk-statistics card for the last 7 days (total new / containing risk signals / ack-pending counts + the top-5 flag distribution).
Migration
20260528130250_add_creation_audit_to_oauth_applications—oauth_applications.created_via(string, defaultweb) +creation_risk_flags(jsonb, default[]) + a partial index onjsonb_array_length(creation_risk_flags) > 0.
Tests
- Model/request/mailer combined: 102+ examples PASS (Phase 2–5e integration regression).
- 6 rounds of Codex review (Phase 2 / 3 / 4 / 5a / 5b / 5b-followup) — every BLOCK resolved.
2026-05-15
- LogiAuth Swift SDK 0.1.2 — added redirect_uri scheme/host/path verification to
handleCallback(ainote 2026-05-15 incident fix) @logi-auth/browser@0.1.0released on npm — a zero-deps PKCE SDK for SPAs- Expanded OIDC Discovery docs —
response_modes_supported,ui_locales_supported,service_documentation,revocation_endpoint_auth_methods_supported(basic/post;noneexcluded),claims_parameter_supported/request_parameter_supported/request_uri_parameter_supported/require_request_uri_registration(explicitly false) /diagnoseendpoint restored — added the missingDiagnoseController+ view (RP self-diagnosis)- docs.1pass.dev track split — added
/tracks/{mobile,web,api}, introduced a line-numbered jump index inllms.txt - Bidirectional Cross-Host Handoff API added (PR #28-32) + global logout
- Console SSO Phase 3 (start.1pass.dev) + desktop Web SSO Phase 1+2 introduced (Mac Safari Universal Link bouncer)
- multi-role join table introduced — role separation per host (Phase 1)
2026-05-11 — Added target_session_token PoP
Added a new credential path so a user who holds both account sessions on the same device can merge accounts without the OTP email round-trip.
- New endpoint
POST /api/v1/me/merge/session-token— issues a 5-minute-TTL token from the target session - The existing
POST /api/v1/me/mergeaccepts eithertarget_session_tokenorotp_code - Providing both credentials at once yields
422 conflicting_credentials - Audit log marker:
merged_via=session_token(distinct from OTP'smerged_via=otp)
For the full flow, see the session-token PoP guide.
2026-05-11 — canonical resolution applied to the Easy Bracket RP
Easy Bracket (RP, https://easy-bracket-lookbook.onrender.com) applied canonical_user_ids resolution — which reflects logi account merges — to its production environment. The ENFORCE_CANONICAL_RESOLUTION=true flip is complete (currently 0 merged users — it will start working automatically from the first future merge).
- Every Pundit policy checks ownership against
user.canonical_user_ids - ActionCable / background jobs / the PttChannel model are canonicalized
- Push-notification fanout deduplicates canonical ids
- Device tokens / API tokens are invalidated immediately on a
user.mergedwebhook
Other RPs can integrate the same pattern. See the RP Integration Guide.
2026-04-27 — Security review wave (Phase 1-14)
A batch of hardening based on a full-codebase security review. For the detailed items, see docs/todo/security-review-findings-2026-04-27.md.
Critical
- P0-1 Device bootstrap re-authentication —
device_secret_digest+ dual-mode (bootstrap → secret revealed once, refresh → digest verification). Blocks re-issuing a PAK for an existing anonymous account using only itsdevice_uuid. - P0-2 Identity reporter capability —
identity_verification_reporterflag +identity_verification_methodsallowlist. Resolves the issue where an arbitrary OAuth app could change a trust level.
High
- Rate limiting — 8 rack-attack throttles (across login/oauth/devices/identity/otp/passkeys/api)
- Webhook SSRF — both registration and dispatch do DNS verification, blocking private/link-local/multicast addresses (IPv4+IPv6). To defend against DNS rebinding, connect directly to the verified IP.
- Webhook secret redesign — store
webhook_secret_plaintextwith ActiveRecord encryption. When the BCrypt fallback is used, add anX-Logi-Secret-Deprecatedheader +Deprecation(RFC 9745). - Passkey UV policy — introduced
purpose=step_up→ enforcesuser_verification: required.otp_verified_atis set only based on whether UV actually happened (authenticator_data.user_verified?). - OAuth authorize return — when not logged in, save
request.fullpathtoreturn_to_after_authenticating→ preserves state/scope/redirect_uri/code_challenge. - Session fixation — call
reset_sessionon successful login (preserve only the necessary keys, then re-store them).
Medium
- New
identity:levelscope — the behavior whereidentity_verified_levelwas automatically included inprofileis deprecated. New apps must explicitly requestidentity:level. Existing apps stay compatible vialegacy_identity_claim=true(a 6-month migration period). - CSP report-only enabled —
default-src 'self',frame-ancestors 'none',/csp-violation-reportsink. The switch to enforce comes after analyzing violation logs. - CORS — dynamic verification of
oauth_applications.allowed_origins. The wildcard + credentials combination is not used. - Secret expiration policy —
client_secret_expires_at/webhook_secret_expires_atwith a 1-year TTL + an audit log alert 30 days before. Issuing a token with an expired client_secret yieldsinvalid_client.
Summary of SDK user impact
- ⚠️
EncryptedSharedPreferences(androidx.security:security-crypto 1.1.0) is deprecated — don't use it in new SDKs. Prefer DataStore + Tink or Ackee Guardian. - ⚠️ Specifying the iOS Keychain option is required:
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly(without the suffix, it syncs to iCloud Keychain). - ⚠️ On
flutter_secure_storage10.0+, you must set up Android backup exclusion (backup_rules.xml) yourself. - ⚠️ The webhook receiving side must handle the
X-Logi-Secret-Deprecated: trueheader + a rotation notice. - New mobile guides: iOS, Android, Flutter, React Native.
v0.1-alpha (2026-04-22 sync)
Completed milestones (see GitHub tags):
m0-bootstrap— Rails 8 scaffold, Cloudflare/Render checklistm1-auth— basic auth (role + device_uuid + lockout)m2-oauth-core— OAuth 2.0 + PKCE S256 + JWKS + Refresh rotationm3-developer-portal— Developer Portal + Admin (iOS 26 Liquid Glass)m4-consent— consent screen + consent recordsm5-cli— Personal API Keys + thelogiCLI (Ruby/Thor)m7-otp— TOTP 2FA + backup codes + a sensitive-operation gatem8-m10-security-observability— Passkey + Login Logs + Webhooksm12-m13— Suspicious Detection + Admin Auditm6-ios-scaffold/m6-m11-ios-mcp— iOS app + MCP serverm14-docs— VitePress + Scalar docs site + OpenAPI 3.1m15-android-scaffold/m15-complete— Android app + Play Integrity round-trip + Sentry2026-04-22—/oauth/revoke(RFC 7009),/oauth/introspect(RFC 7662), a recurring job to purge sign-in history after 90 days
Known limitations
- Production deployment to Render / Cloudflare / GitHub Pages is not complete yet
- Push notifications (APNs/FCM) not implemented
- Play Integrity production decode and
ANDROID_APP_CERT_SHA256injection not yet complete - The iOS associated domain migration to
api.1pass.devis complete (v0.4, 2026-04-22)
Roadmap (β)
- β1: dynamic scope + required marking (in progress)
- β2: custom claims (
User#custom_claimsimplemented) - β3: sign-in history alerts + APNs/FCM
- β5: mobile production hardening (Play Integrity decode, cert fingerprint, associated domain cleanup)