finishSignIn
uses location
If the page was opened coming back from signing in (its fragment holds the answer): finish it, keep who's signed in,
tell the app's server (with server: #rg75eniw), and go back where it left. Who signed in, or undefined if
the page wasn't coming back; throws what went wrong.
import { ACCOUNT_EVENT, accountOf, comingBack, configureBrowser, serviceDid, SIGN_IN_LXM, SIGNED_IN, SIGNING_IN, takeSignIn, } from "#codebase/tcmts/atproto"; import type { Account, SignInOptions } from "#codebase/tcmts/atproto"; import { finalizeAuthorization, OAuthUserAgent } from "@atcute/oauth-browser-client"; export async function finishSignIn(): Promise<Account | undefined> { const params = new URLSearchParams(location.hash.slice(1)); if (!params.has("state") || !(params.has("code") || params.has("error"))) return undefined; // (so it isn't used twice) history.replaceState(null, "", location.pathname + location.search); const asked = JSON.parse(sessionStorage.getItem(SIGNING_IN) ?? "null") as | (SignInOptions & { returnTo?: string }) | null; sessionStorage.removeItem(SIGNING_IN); if (!asked) throw new Error("This sign-in wasn't started here: sign in again."); await configureBrowser(asked); const { session } = await finalizeAuthorization(params); const did = session.info.sub; let account: Account = { did }; if (asked.server) { const agent = new OAuthUserAgent(session); const q = new URLSearchParams({ aud: serviceDid(location.origin), lxm: SIGN_IN_LXM, exp: String(Math.floor(Date.now() / 1000) + 120), }); const res = await agent.handle(`/xrpc/com.atproto.server.getServiceAuth?${q}`); const body = (await res.json().catch(() => ({}))) as { token?: string; message?: string }; if (!res.ok || !body.token) throw new Error(`Your PDS wouldn't sign you in here: ${body.message ?? res.status}`); account = await takeSignIn(body.token); } else account = await accountOf(did); localStorage.setItem( SIGNED_IN, JSON.stringify({ ...account, scope: asked.scope, ...(asked.client ? { client: asked.client } : {}), ...(asked.server ? { server: true } : {}), }), ); window.dispatchEvent(new Event(ACCOUNT_EVENT)); const here = location.pathname + location.search; const back = comingBack(asked.returnTo ?? null, here); // (told to the server, the page is made again with the sign-in; else it goes on as it is, unless it's going elsewhere) if (back !== here || asked.server) location.replace(back); return account; }
uses
- tcmts.atproto.ACCOUNT_EVENT
- tcmts.atproto.Account
- tcmts.atproto.SIGNED_IN
- tcmts.atproto.SIGNING_IN
- tcmts.atproto.SIGN_IN_LXM
- tcmts.atproto.SignInOptions
- tcmts.atproto.accountOf
- tcmts.atproto.comingBack
- tcmts.atproto.configureBrowser
- tcmts.atproto.serviceDid
- tcmts.atproto.takeSignIn