Docs / Start

Stable

Build your first Login with Atmosphere flow

Add a shared account picker, verify the signed account selection, then start your own AT Protocol OAuth flow.

Use the hosted picker for account selection, not token brokerage.Verify the selection token before trusting the chosen DID or handle.Complete AT Protocol OAuth in your app after selection.

Flow

Login with Atmosphere selects, your app authorizes

The picker only answers one question: which Atmosphere account does the user want to use? Your app still owns scopes, grants, sessions, refresh behavior, and logout.

Local development wording

Developers usually run a local app while integrating. ATProto’s development shortcut uses http://localhost/ as a special client ID, while local callbacks should use loopback IP return URIs such as http://127.0.0.1:5173/callback. Production uses exact HTTPS return URIs.

Minimal implementation

01

Create the app profile and environment

Create the public app profile once, then add a development or production environment with its client ID and exact return URI. The picker derives the name, homepage, and logo from the profile.

02

Add the SDK button

Pass the registered client ID and return URI to the browser SDK.

03

Verify the callback

Use the server helper or your own JWT verifier to validate the selection token.

04

Continue OAuth

Start AT Protocol OAuth and verify the returned sub DID according to the AT Protocol OAuth profile.

Button
<script src="https://login.atmosphereaccount.com/atmosphere-login.js" defer></script>

<button
  data-atmosphere-login
  data-client-id="https://app.example.com/oauth/client-metadata.json"
  data-return-uri="https://app.example.com/auth/atmosphere/selected"
  data-app-name="Example App"
></button>
Selection callback
const verified = await verifyAtmosphereLoginCallback({
  url: request.url,
  publicJwk,
  expectedIssuer: "https://login.atmosphereaccount.com",
  expectedClientId,
  expectedReturnUri,
  expectedState,
  replayStore,
});

if (!verified.ok) throw new Error(verified.error);

return startAtprotoOAuth({
  loginHint: verified.claims.handle || verified.claims.sub,
});

Move from local dev to production

Local URLs are for integration only. Before requesting trust, move every public identity and return URI to HTTPS.

  • Use a production HTTPS client ID URL.
  • Use exact HTTPS allowed return URIs for every callback.
  • Serve a recognizable HTTPS logo.
  • Publish /.well-known/atmosphere-login.json on the app homepage origin.
  • Run production checks from the app detail page.
  • Request trusted review only after the picker test passes.
On this page

Next steps

Keep building