Skip to content

⭐ Quickstart for agents (RP integration runbook)

Where this page sits When an AI agent receives a request like "add logi (1pass) login to this project," fetch this page first. The 60+ other pages on docs.1pass.dev are reference material that branches from this page. This page covers only "what to do, in what order, on which track, and what never to do." Details and code examples are linked out — not a single line of code is inlined here.

Before starting, skim the changelog once (avoids deprecated patterns — see F8).


Step 0 — Auto-detect the track and confirm with the user

Before any real work, lock in exactly one track. Without a confirmed track, the agent will install the wrong SDK.

File / signatureTrack
Info.plist, *.xcodeproj, Package.swift📱 mobile (iOS Swift)
build.gradle*, AndroidManifest.xml📱 mobile (Android Kotlin)
pubspec.yaml with a flutter: key📱 mobile (Flutter)
package.json with a react-native dependency📱 mobile (React Native)
Gemfile with rails🌐 web (Rails)
package.json with a next dependency🌐 web (Next.js)
package.json with an express dependency🌐 web (Express)
None of the above — CLI, daemon, or webhook receiver only🔧 api

If multiple signatures match, ask the user — never guess. Have the user confirm the detected track before any work begins.

Track-specific guides: 📱 mobile · 🌐 web · 🔧 api.


Responsibility labels

Each step header carries one of these labels:

  • [agent] — work the agent can complete in code on its own
  • [human] — work the user must do in a console or secret store. The agent stops and says "your turn — next action: ..."
  • [agent + human] — the agent prepares it; the user clicks or approves once

The 8-step execution order

Step 1 · Pick the client type — [agent]

⚠️ Decide before registering. logi locks client type as immutable at registration time (public-vs-confidential is final after registration). A wrong choice means creating a brand new RP.

Decide based on track and whether secrets can be stored:

TrackClient typeWhy
📱 mobilePublic + PKCEclient_secret cannot be embedded in an app binary (RFC 8252)
🌐 web (SSR with a backend)Confidential + PKCEThe server can hold the secret
🌐 web (SPA only, no backend)Public + PKCEA browser bundle cannot hide a secret
🔧 api (server-to-server)Confidential + device flow / PAKlogi does NOT support the client_credentials grant (errors.md)

Detailed decision rules: oauth/public-vs-confidential, oauth/public-clients, oauth/recommended-architecture.

Step 1.5 · Pick the scopes — [agent]

These define what user data the RP receives from logi. Scopes are pinned at registration via allowed_scopes. Read the drift behavior before deciding.

  • Default starting point: openid profile email (enough for most RPs)
  • Add as needed: phone, or a custom namespaced scope
  • Drift behavior: under the default policy (block), requesting any scope not in allowed_scopes is rejected with invalid_scope. Only apps explicitly relaxed to log_only/alert by an admin get the old silent-drop behavior — keep your authorize request scopes identical to the registered list.

Verification: the scopes you chose match allowed_scopes at registration, and the authorize request in code uses the same list.

Step 2 · Register the RP app — [human] (or [agent + human] when using the CLI)

Using the type and scopes from Step 1 and 1.5, register the RP in the console or via the CLI and obtain a client_id (plus a client_secret for confidential clients). The agent must not store the secret in its own memory — ask the user where to keep it: 1Password, Keychain, or .env.

Verification: client_id starts with logi_. For confidential clients, client_secret starts with logi_secret_.

Step 3 · Drop in the track-specific code — [agent]

This is where the agent writes the most code. Apply only the one page for your track. Merging from multiple track pages at once will pull in deprecated patterns.

Track / stackPage
iOS Swiftintegrations/swift
Android Kotlinintegrations/android (with the kotlin addendum)
Flutterintegrations/flutter
React Nativeintegrations/react-native
Rails 8integrations/rails
Next.js (App Router)integrations/nextjs
Express.jsintegrations/express
Login button UIintegrations/buttons

Verification: the build passes — npm run build, bundle exec rails routes, Xcode build, or equivalent.

Step 4 · Verify the PKCE and state implementation — [agent]

logi only accepts S256 and rejects plain. An SDK used as-is is usually fine, but a hand-rolled implementation must be checked.

Verification checkpoints:

  • code_verifier is URL-safe base64, length in [43, 128] (RFC 7636)
  • code_challenge_method=S256 is included in the /oauth/authorize request
  • code_verifier is stored in the session or Keychain and reused for the /oauth/token call
  • state is randomly generated, stored in the session, and verified at the callback (mitigates F3)
  • id_token verification checks both iss="logi" and aud=LOGI_CLIENT_ID (mitigates F4)

Step 5 · Register the redirect_uri values — [agent + human]

🚨 The #1 OAuth error (per OneUptime stats). Cutting corners here guarantees a production failure.

The agent must list every redirect_uri the RP will use and tell the user to register them all in the console:

  • Local dev — for example http://localhost:3000/auth/logi/callback
  • Staging — for example https://staging.example.com/auth/logi/callback
  • Production — for example https://example.com/auth/logi/callback
  • Mobile (custom scheme) — for example com.example.myapp://oauth/1pass/callback

The rule: exact match on everything — trailing slash, case, query, port. Wildcards are rejected.

Verification: the URI list registered in the console matches the LOGI_REDIRECT_URI environment variable character-for-character.

Step 6 · Webhook receiver and signature verification — [agent]

🚨 The step agents skip most often. Leaving "verify signature" as a // TODO exposes the RP to forged webhooks. If a TODO comment remains, this step is not done.

Verification: the PR must include a test case that returns 401 for requests with an invalid X-Logi-Signature.

Step 6.5 · Handle refresh token rotation — [agent]

logi issues a new refresh token on every response and revokes the entire token family on reuse detection. An RP that ignores rotation will log every user out on a single network failure.

Verification:

  • Replace and persist the new refresh_token from every /oauth/token response immediately
  • Storage: encrypted DB on the server, Keychain (iOS) or Keystore (Android) on mobile, and HttpOnly Secure SameSite=Strict cookies on the web
  • A 400 invalid_grant response means family revoke or expiry — force re-authentication. Never silently retry forever.

Step 7 · First-time signup form — [agent]

logi returns roughly sub, email, and optionally nickname. If the RP needs more fields (role, organization, terms acceptance, and so on), implement a form that runs only on the first login. Showing it every time breaks the UX.

Verification: logging out and logging back in with the same logi account does not re-show the form.

Step 8 · End-to-end test plus error and rate-limit handling — [agent + human]

Run the full flow in a real browser or device, and handle the error codes and rate limits the RP will hit in production at the code level:

Verification (full loop):

  1. /auth/logi/start redirects to /oauth/authorize
  2. The user approves via logi app push or QR scan
  3. The RP callback fires, /oauth/token exchange succeeds, and id_token verification passes (iss and aud)
  4. /oauth/userinfo returns the user object
  5. A user.updated event arrives at the webhook receiver and signature verification passes
  6. On a 429 response, the client backs off according to Retry-After (sleep and retry)

Track branching table

How each step differs across tracks, at a glance:

Step📱 mobile🌐 web🔧 api
1 client typePublic + PKCE, alwaysConfidential recommended (Public for SPA-only)Confidential + device / PAK
1.5 scopesopenid profile email defaultopenid profile email defaultMinimal (profile is usually enough)
2 RP registration✅ Public✅ Confidential✅ Confidential
3 code drop-inswift / kotlin / flutter / RNrails / nextjs / expressapi track page
4 PKCE + stateRequiredRequired (both SPA and SSR)Device flow does not need PKCE
5 redirect_uriCustom scheme recommendedhttps URLN/A (device flow)
6 webhook✅ (most common consumer)
6.5 refresh rotation✅ Keychain / Keystore✅ HttpOnly cookie✅ Encrypted DB
7 first-time signupUsually not needed (no UI)
8 e2eReal device plus KakaoTalk / Naver in-app escapelocalhost plus stagingcurl alone is enough

🚨 Known pitfalls (F1-F8) — ordered by frequency

Ignoring this catalog leads directly to production incidents.

F1. redirect_uri mismatch (the #1 OAuth incident)

F2. Skipping webhook signature verification (// TODO: verify)

  • Symptoms: forged webhooks pollute the RP database — typically caught only during a post-incident audit
  • Causes: the agent ships the receiver but defers verification
  • Mitigation: guide/webhook-verification — both signature formats must be handled. Use a tested template: templates/webhook

F3. Missing or unverified state parameter

  • Symptoms: CSRF lets an attacker bind their own logi account to the victim's RP session
  • Causes: no state on the authorize request, or no comparison against the stored value at the callback
  • Mitigation: guide/security#state

F4. id_token verification skips iss or aud

  • Symptoms: confused-deputy bug — tokens from another OIDC IdP are accepted as logi tokens
  • Causes: only the JWT signature is verified; claims are not
  • Mitigation: oauth/jwks, guide/security

F5. Refresh token reuse and unhandled family revoke

  • Symptoms: a single network failure logs every user out; the client retries 400 invalid_grant forever
  • Causes: the new refresh token is not persisted after rotation, or family-revoke 400 invalid_grant responses are retried as generic errors
  • Mitigation: oauth/flow (reuse detection → family revoke + 400 spec), oauth/public-clients
  • Symptoms: ainote incident on 2026-05-15 — an unrelated deep link in flight was injected into the OAuth parser, producing a bogus missingCode
  • Causes: the RP app claims a universal link on the same host as the IdP
  • Mitigation: use a custom scheme callback (com.example.myapp://oauth/1pass/callback) — integrations/swift, integrations/react-native, guide/universal-links

F7. KakaoTalk and Naver in-app browsers

  • Symptoms: OAuth is blocked inside the in-app browser (passkey and SSO do not work)
  • Mitigation: use an escape route — guide/demo-page-walkthrough

F8. client_secret in a public client

  • Symptoms: the secret is embedded in a mobile app or SPA binary and extracted via reverse engineering
  • Mitigation: Public + PKCE only — oauth/public-clients

Additional pitfalls (iOS scheme / Android App Link host sharing) are covered in the pitfalls sections of integrations/swift and integrations/android.


✅ Self-verify checklist before reporting completion

Eight items the agent must confirm itself before telling the user the work is done:

  • [ ] Step 1 and 1.5 — the rationale for client type and scope choice is recorded in the PR description and matches the registration result
  • [ ] Step 2client_id starts with logi_; console or CLI registration is complete; the secret lives in 1Password, Keychain, or .env (never in code or git)
  • [ ] Step 3 — only one track page was applied; the build passes
  • [ ] Step 4code_challenge_method=S256, state verification, and id_token iss and aud checks all pass
  • [ ] Step 5 — every redirect_uri (local, staging, prod, mobile scheme) is registered in the console and matches the environment variable character-for-character
  • [ ] Step 6 — zero TODO comments in webhook signature verification code; a 401 test case is included
  • [ ] Step 6.5 — refresh token rotation works: new refresh token is persisted immediately, and 400 invalid_grant triggers re-authentication (family revoke or expiry)
  • [ ] Step 7 and 8 — the first-time signup form does not re-appear on re-login; the 6-step e2e flow passes (authorize → approve → callback → token → userinfo → webhook plus 429 backoff)

If even one item is unchecked, report "not done — please continue with the next step" to the user. Do not file a false "complete" report.


❌ Anti-patterns — do not do these

Avoid these before any production push. If the agent's PR contains any of them, self-block the PR.

  • ❌ Using the Implicit Flow — logi rejects it. Only Authorization Code + PKCE is supported
  • ❌ Using the Password Grant — logi rejects it
  • ❌ Exposing client_secret in a client (mobile binary, SPA bundle, or public git repo)
  • ❌ Wildcards or partial matches for redirect_uri — only exact matches pass
  • ❌ Skipping webhook signature verification or leaving // TODO: verify
  • ❌ Using PKCE plain — only S256 is accepted
  • ❌ Omitting or failing to verify the state parameter — CSRF exposure (F3)
  • ❌ Skipping iss or aud in id_token verification — token forgery exposure (F4)
  • ❌ Infinite retry on refresh token failure — ignoring family revoke force-logs-out every user
  • ❌ Merging from multiple track pages at once — pulls in deprecated patterns

Maintenance note (avoiding stale skills)

The skills and templates shipped alongside this page go stale over time. At the start of any work, confirm two things:

  1. Recent entries in reference/changelog — new grant types, deprecated scopes, breaking changes
  2. guide/ai-assistants — the current skill catalog for Claude Code, Cursor, and Codex

A skill cached for more than three months can ship a deprecated pattern the agent has never seen. Refresh it.


What's next

Identity가 제품의 신뢰를 만듭니다.