@byggnode/auth-client 0.0.2 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,8 +48,10 @@ await session.redirectToLogin();
48
48
  // Check silently; the callback gets ?error=login_required when not signed in
49
49
  await session.redirectToLogin({ prompt: "none" });
50
50
 
51
- // Or send a magic link from your own form
51
+ // Or send a magic link from your own form. The mail also has a 6-digit
52
+ // code: let the user type it here and stay in the app
52
53
  await session.requestMagicLink(email);
54
+ const res = await session.loginWithCode(email, code); // 400 invalid_code on a wrong code
53
55
 
54
56
  // Invite a user (Auth sends mail and applies role on accept)
55
57
  await session.createInvite({ email, role: "cms" });
@@ -407,6 +407,21 @@ class AuthClient {
407
407
  }),
408
408
  });
409
409
  }
410
+ /**
411
+ * The 6-digit code from the mail `requestMagicLink()` sent, typed in the
412
+ * app's own form. Logs in without leaving the app (no SSO cookie).
413
+ */
414
+ async loginWithCode(email, code) {
415
+ const res = await authJson(this.fetchFn, this.url("/magic-link/code"), {
416
+ method: "POST",
417
+ body: JSON.stringify({ email, app: this.config.appSlug, code }),
418
+ });
419
+ if (res.status !== 200 || !res.body.code) {
420
+ const body = { error: res.body.error ?? "invalid_code" };
421
+ return { status: res.status, body: body };
422
+ }
423
+ return this.exchangeCode(res.body.code);
424
+ }
410
425
  /** Authenticated `POST /invites`. Auth owns mail + accept. */
411
426
  async createInvite(input) {
412
427
  return this.request("/invites", {
@@ -680,6 +695,12 @@ class SessionStore {
680
695
  async requestMagicLink(email, intent = "login") {
681
696
  return this.client.requestMagicLink(email, intent);
682
697
  }
698
+ /** The 6-digit code from that mail, typed in the app's own form. */
699
+ async loginWithCode(email, code) {
700
+ const result = await this.client.loginWithCode(email, code);
701
+ this.session.set(this.client.getSession());
702
+ return result;
703
+ }
683
704
  async createInvite(input) {
684
705
  const result = await this.client.createInvite(input);
685
706
  this.session.set(this.client.getSession());
@@ -1 +1 @@
1
- {"version":3,"file":"byggnode-auth-client.mjs","sources":["../../src/lib/session-expiry.ts","../../src/lib/config.ts","../../src/lib/http.ts","../../src/lib/storage.ts","../../src/lib/types.ts","../../src/lib/pkce.ts","../../src/lib/urls.ts","../../src/lib/client.ts","../../src/lib/tokens.ts","../../src/lib/session.ts","../../src/lib/provide.ts","../../src/lib/guards.ts","../../src/lib/grant-dialog.ts","../../src/byggnode-auth-client.ts"],"sourcesContent":["export const ACCESS_REFRESH_SKEW_MS = 60_000;\n\nexport function jwtExpMs(accessToken: string): number | null {\n const parts = accessToken.split(\".\");\n if (parts.length < 2 || !parts[1]) return null;\n try {\n const raw = parts[1].replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const pad = raw.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (raw.length % 4));\n const json = atob(raw + pad);\n const exp = (JSON.parse(json) as { exp?: unknown }).exp;\n return typeof exp === \"number\" && Number.isFinite(exp) ? exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nexport function accessTokenExpiresAtMs(session: {\n access_token?: string;\n expires_at?: number;\n}): number | null {\n if (typeof session.expires_at === \"number\" && Number.isFinite(session.expires_at)) {\n return session.expires_at;\n }\n return jwtExpMs(session.access_token ?? \"\");\n}\n\nexport function accessTokenNeedsRefresh(\n expiresAtMs: number | null,\n now = Date.now(),\n skewMs = ACCESS_REFRESH_SKEW_MS,\n): boolean {\n if (expiresAtMs == null) return false;\n return expiresAtMs - now <= skewMs;\n}\n\nexport function withExpiresAt<\n T extends { access_token: string; expires_in?: number; expires_at?: number },\n>(session: T, now = Date.now()): T & { expires_at?: number } {\n const fromJwt = jwtExpMs(session.access_token);\n const fromTtl =\n typeof session.expires_in === \"number\" && session.expires_in > 0\n ? now + session.expires_in * 1000\n : null;\n const expiresAt = session.expires_at ?? fromJwt ?? fromTtl ?? undefined;\n return expiresAt == null ? session : { ...session, expires_at: expiresAt };\n}\n","import { ACCESS_REFRESH_SKEW_MS } from \"./session-expiry\";\n\nexport type AuthClientConfig = {\n /** IdP origin, e.g. `https://auth.byggnode.no`. Empty string = same origin. */\n authOrigin: string;\n /** Registered app slug sent on magic-link / login redirect / token exchange. */\n appSlug: string;\n /** Allowed callback URL; verify redirects here with `?code=`. */\n returnUrl: string;\n /** Browser storage key (localStorage by default). Default matches the auth console (`auth.session`). */\n storageKey?: string;\n /** Path on the IdP for the hosted login page. Default `/login`. */\n loginPath?: string;\n /** Path on the IdP for the SSO redirect. Default `/authorize`. */\n authorizePath?: string;\n /** Refresh this many ms before access-token expiry. Default 60s. */\n refreshSkewMs?: number;\n /** Router path SessionStore uses after a failed refresh. Default `/login?expired=1`. */\n expiredPath?: string;\n};\n\nexport type ResolvedAuthClientConfig = {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n storageKey: string;\n loginPath: string;\n authorizePath: string;\n refreshSkewMs: number;\n expiredPath: string;\n};\n\nexport function resolveAuthClientConfig(\n config: AuthClientConfig,\n): ResolvedAuthClientConfig {\n const appSlug = config.appSlug.trim();\n const returnUrl = config.returnUrl.trim();\n if (!appSlug) {\n throw new Error(\"provideAuthClient: appSlug is required\");\n }\n if (!returnUrl) {\n throw new Error(\"provideAuthClient: returnUrl is required\");\n }\n return {\n authOrigin: config.authOrigin.replace(/\\/$/, \"\"),\n appSlug,\n returnUrl,\n storageKey: config.storageKey?.trim() || \"auth.session\",\n loginPath: config.loginPath?.trim() || \"/login\",\n authorizePath: config.authorizePath?.trim() || \"/authorize\",\n refreshSkewMs: config.refreshSkewMs ?? ACCESS_REFRESH_SKEW_MS,\n expiredPath: config.expiredPath?.trim() || \"/login?expired=1\",\n };\n}\n","import type { AuthApiResult } from \"./types\";\n\nexport function readErrorCode(body: unknown): string {\n if (!body || typeof body !== \"object\") return \"\";\n const error = (body as { error?: unknown }).error;\n return typeof error === \"string\" ? error : \"\";\n}\n\nexport function isUnauthorized(status: number, body: unknown): boolean {\n if (status === 401) return true;\n return readErrorCode(body) === \"unauthorized\";\n}\n\nexport function jsonHeaders(\n init: RequestInit & { token?: string } = {},\n): Headers {\n const headers = new Headers(init.headers);\n if (init.body && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n if (init.token) headers.set(\"authorization\", `Bearer ${init.token}`);\n return headers;\n}\n\nexport async function parseJsonResponse<T>(\n res: Response,\n): Promise<AuthApiResult<T>> {\n const body = (await res.json().catch(() => ({}))) as T;\n return { status: res.status, body };\n}\n\nexport type AuthFetchFn = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function authJson<T>(\n fetchFn: AuthFetchFn,\n url: string,\n init: RequestInit & { token?: string } = {},\n): Promise<AuthApiResult<T>> {\n const { token, ...rest } = init;\n const res = await fetchFn(url, { ...rest, headers: jsonHeaders(init) });\n return parseJsonResponse<T>(res);\n}\n","export type SessionStorageLike = {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n};\n\nexport function createMemoryStorage(): SessionStorageLike {\n const map = new Map<string, string>();\n return {\n getItem(key) {\n return map.get(key) ?? null;\n },\n setItem(key, value) {\n map.set(key, value);\n },\n removeItem(key) {\n map.delete(key);\n },\n };\n}\n\n/**\n * Prefer localStorage so IdP sessions survive new tabs and browser restarts.\n * Fall back to in-memory storage when localStorage is unavailable (private\n * mode / non-browser); sessionStorage is a last resort if localStorage throws\n * but sessionStorage works.\n */\n/** One-shot: copy auth.session from sessionStorage → localStorage (cutover). */\nfunction migrateSessionKeyToLocal(key = \"auth.session\"): void {\n try {\n if (typeof localStorage === \"undefined\" || typeof sessionStorage === \"undefined\") return;\n if (localStorage.getItem(key)) return;\n const raw = sessionStorage.getItem(key);\n if (!raw) return;\n localStorage.setItem(key, raw);\n sessionStorage.removeItem(key);\n } catch {\n // ignore quota / private mode\n }\n}\n\nexport function defaultSessionStorage(): SessionStorageLike {\n try {\n if (typeof localStorage !== \"undefined\") {\n migrateSessionKeyToLocal();\n return localStorage;\n }\n } catch {\n // private mode / non-browser\n }\n try {\n if (typeof sessionStorage !== \"undefined\") return sessionStorage;\n } catch {\n // private mode / non-browser\n }\n return createMemoryStorage();\n}\n\nexport function readStoredJson<T>(\n storage: SessionStorageLike,\n key: string,\n): T | null {\n try {\n const raw = storage.getItem(key);\n if (!raw) return null;\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n","export type AuthUser = {\n id: string;\n email: string;\n};\n\nexport type AppInfo = {\n slug: string;\n name: string;\n active?: boolean;\n allowed_origins?: string[];\n redirect_uris?: string[];\n};\n\nexport type RoleScope = {\n role: string;\n orgnr: string | null;\n};\n\nexport type SessionPayload = {\n access_token: string;\n refresh_token: string;\n token_type?: string;\n expires_in?: number;\n expires_at?: number;\n session_id?: string;\n user: AuthUser;\n app: { slug: string; name: string };\n roles: string[];\n permissions: string[];\n scopes: RoleScope[];\n};\n\nexport type AuthApiResult<T> = {\n status: number;\n body: T;\n};\n\nexport type MagicLinkResponse = {\n ok?: boolean;\n error?: string;\n dev_token?: string;\n};\n\nexport type InviteRequest = {\n email: string;\n role: string;\n app?: string;\n orgnr?: string;\n return_url?: string;\n};\n\nexport type InviteResponse = {\n ok?: boolean;\n error?: string;\n invite?: {\n id: string;\n email: string;\n role: string;\n app: string;\n orgnr: string | null;\n status?: string;\n expires_at: string;\n };\n dev_token?: string;\n};\n\nexport type TokenErrorBody = {\n error?: string;\n};\n\nexport type RoleRow = {\n slug: string;\n name: string;\n description?: string | null;\n permissions: string[];\n};\n\nexport function isSessionPayload(value: unknown): value is SessionPayload {\n if (!value || typeof value !== \"object\") return false;\n const rec = value as Partial<SessionPayload>;\n return (\n typeof rec.access_token === \"string\" &&\n rec.access_token.length > 0 &&\n typeof rec.refresh_token === \"string\" &&\n !!rec.user &&\n typeof rec.user.id === \"string\" &&\n typeof rec.user.email === \"string\" &&\n !!rec.app &&\n typeof rec.app.slug === \"string\" &&\n Array.isArray(rec.roles) &&\n Array.isArray(rec.permissions)\n );\n}\n","function base64url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n}\n\n/** RFC 7636 S256 pair: 43-char verifier, base64url(sha256(verifier)) challenge. */\nexport async function createPkcePair(): Promise<{\n verifier: string;\n challenge: string;\n}> {\n const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(verifier),\n );\n return { verifier, challenge: base64url(new Uint8Array(digest)) };\n}\n","export function joinAuthUrl(origin: string, path: string): string {\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n if (!origin) return normalizedPath;\n return `${origin.replace(/\\/$/, \"\")}${normalizedPath}`;\n}\n\nexport function isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport function resolveReturnUrl(\n requested: string | null | undefined,\n fallback: string,\n): string {\n if (requested && isHttpUrl(requested)) return requested;\n return fallback;\n}\n\nexport function readCallbackCode(searchOrUrl: string): string | null {\n const raw = searchOrUrl.trim();\n if (!raw) return null;\n try {\n if (raw.includes(\"://\") || raw.startsWith(\"/\") || raw.startsWith(\"?\")) {\n const url = raw.includes(\"://\")\n ? new URL(raw)\n : new URL(raw, \"http://auth.local\");\n return url.searchParams.get(\"code\");\n }\n } catch {\n // treat as a bare code below\n }\n if (raw.includes(\"=\")) {\n return new URLSearchParams(raw.startsWith(\"?\") ? raw.slice(1) : raw).get(\n \"code\",\n );\n }\n return raw;\n}\n\n/** `error` on the callback URL, e.g. `login_required` after `prompt=none`. */\nexport function readCallbackError(searchOrUrl: string): string | null {\n const raw = searchOrUrl.trim();\n if (!raw.includes(\"=\")) return null;\n try {\n const url = raw.includes(\"://\") ? new URL(raw) : new URL(raw, \"http://auth.local\");\n return (\n url.searchParams.get(\"error\") ??\n new URLSearchParams(raw.startsWith(\"?\") ? raw.slice(1) : raw).get(\"error\")\n );\n } catch {\n return null;\n }\n}\n\nexport function buildAuthorizeUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n codeChallenge: string;\n authorizePath?: string;\n prompt?: \"none\";\n}): string {\n const url = new URL(\n joinAuthUrl(opts.authOrigin, opts.authorizePath ?? \"/authorize\"),\n \"http://auth.local\",\n );\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n url.searchParams.set(\"code_challenge\", opts.codeChallenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n if (opts.prompt) url.searchParams.set(\"prompt\", opts.prompt);\n return opts.authOrigin ? url.toString() : `${url.pathname}${url.search}`;\n}\n\n/** Auth `GET /logout`: ends SSO and every app session it issued. */\nexport function buildLogoutUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n}): string {\n const url = new URL(joinAuthUrl(opts.authOrigin, \"/logout\"), \"http://auth.local\");\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n return opts.authOrigin ? url.toString() : `${url.pathname}${url.search}`;\n}\n\nexport function buildLoginUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n loginPath?: string;\n}): string {\n const path = joinAuthUrl(opts.authOrigin, opts.loginPath ?? \"/login\");\n const url = path.includes(\"://\")\n ? new URL(path)\n : new URL(path, \"http://auth.local\");\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n if (path.includes(\"://\")) return url.toString();\n return `${url.pathname}${url.search}`;\n}\n","import {\n resolveAuthClientConfig,\n type AuthClientConfig,\n type ResolvedAuthClientConfig,\n} from \"./config\";\nimport {\n authJson,\n isUnauthorized,\n readErrorCode,\n type AuthFetchFn,\n} from \"./http\";\nimport {\n accessTokenExpiresAtMs,\n accessTokenNeedsRefresh,\n withExpiresAt,\n} from \"./session-expiry\";\nimport {\n createMemoryStorage,\n defaultSessionStorage,\n readStoredJson,\n type SessionStorageLike,\n} from \"./storage\";\nimport {\n isSessionPayload,\n type AuthApiResult,\n type InviteRequest,\n type InviteResponse,\n type MagicLinkResponse,\n type SessionPayload,\n type TokenErrorBody,\n} from \"./types\";\nimport { createPkcePair } from \"./pkce\";\nimport {\n buildAuthorizeUrl,\n buildLoginUrl,\n buildLogoutUrl,\n joinAuthUrl,\n readCallbackCode,\n readCallbackError,\n} from \"./urls\";\n\n/** The subset of the Web Locks API the client uses. */\nexport type LockManagerLike = {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n};\n\nexport type AuthClientOptions = {\n storage?: SessionStorageLike;\n /** Holds the PKCE verifier between /authorize and /callback. Default sessionStorage. */\n pkceStorage?: SessionStorageLike;\n fetch?: AuthFetchFn;\n /** Serializes refresh across tabs. Default `navigator.locks` when available. */\n locks?: LockManagerLike | null;\n};\n\nexport type RedirectToLoginOptions = {\n /** `none`: come back with `?error=login_required` instead of showing the login page. */\n prompt?: \"none\";\n assign?: (url: string) => void;\n};\n\n/** Outcome of a refresh_token grant attempt. */\ntype RefreshOutcome = \"refreshed\" | \"invalid\" | \"transient\";\n\nconst INVALID_REFRESH_ERRORS = new Set([\n \"invalid_refresh\",\n \"refresh_expired\",\n \"refresh_token_required\",\n \"invalid_grant\",\n]);\n\nfunction isInvalidRefreshResponse(status: number, body: unknown): boolean {\n if (status === 401) return true;\n if (status !== 400) return false;\n const code = readErrorCode(body);\n return INVALID_REFRESH_ERRORS.has(code);\n}\n\nexport class AuthClient {\n readonly config: ResolvedAuthClientConfig;\n private readonly storage: SessionStorageLike;\n private readonly pkceStorage: SessionStorageLike;\n private readonly fetchFn: AuthFetchFn;\n private readonly locks: LockManagerLike | null;\n private readonly listeners = new Set<(session: SessionPayload | null) => void>();\n private current: SessionPayload | null;\n private refreshInFlight: Promise<RefreshOutcome> | null = null;\n\n constructor(config: AuthClientConfig, options: AuthClientOptions = {}) {\n this.config = resolveAuthClientConfig(config);\n this.storage = options.storage ?? defaultSessionStorage();\n this.pkceStorage = options.pkceStorage ?? defaultPkceStorage();\n this.fetchFn = options.fetch ?? fetch;\n this.locks =\n options.locks === undefined ? defaultLocks() : options.locks;\n this.current = this.loadFromStorage();\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"storage\", (event) => {\n if (event.key === this.config.storageKey || event.key === null) {\n this.reloadFromStorage();\n }\n });\n }\n }\n\n /** Called whenever the session changes, including from another tab. */\n onChange(listener: (session: SessionPayload | null) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /** Adopt what another tab (or app on this origin) stored. */\n reloadFromStorage(): SessionPayload | null {\n this.current = this.loadFromStorage();\n this.emit();\n return this.current;\n }\n\n private emit(): void {\n for (const listener of this.listeners) listener(this.current);\n }\n\n private get pkceKey(): string {\n return `${this.config.storageKey}.pkce`;\n }\n\n getSession(): SessionPayload | null {\n return this.current;\n }\n\n get token(): string {\n return this.current?.access_token ?? \"\";\n }\n\n get user(): SessionPayload[\"user\"] | null {\n return this.current?.user ?? null;\n }\n\n get app(): SessionPayload[\"app\"] | null {\n return this.current?.app ?? null;\n }\n\n get roles(): string[] {\n return this.current?.roles ?? [];\n }\n\n get permissions(): string[] {\n return this.current?.permissions ?? [];\n }\n\n can(permission: string): boolean {\n return this.permissions.includes(permission);\n }\n\n setSession(session: SessionPayload): SessionPayload {\n const next = withExpiresAt(session);\n this.current = next;\n this.storage.setItem(this.config.storageKey, JSON.stringify(next));\n this.emit();\n return next;\n }\n\n clearSession(): void {\n this.current = null;\n this.storage.removeItem(this.config.storageKey);\n this.emit();\n }\n\n /** Hosted login page without SSO (`app` + `return_url`). */\n loginUrl(): string {\n return buildLoginUrl(this.config);\n }\n\n /**\n * Auth `GET /authorize` with a fresh PKCE pair. Signed in on Auth already:\n * straight back with a code. Otherwise the hosted login page.\n */\n async authorizeUrl(prompt?: \"none\"): Promise<string> {\n const { verifier, challenge } = await createPkcePair();\n this.pkceStorage.setItem(this.pkceKey, verifier);\n return buildAuthorizeUrl({\n authOrigin: this.config.authOrigin,\n appSlug: this.config.appSlug,\n returnUrl: this.config.returnUrl,\n authorizePath: this.config.authorizePath,\n codeChallenge: challenge,\n prompt,\n });\n }\n\n /** Send the browser through Auth `/authorize` (SSO across app domains). */\n async redirectToLogin(\n options: RedirectToLoginOptions | ((url: string) => void) = {},\n ): Promise<void> {\n const { prompt, assign = defaultAssign } =\n typeof options === \"function\" ? { assign: options } : options;\n assign(await this.authorizeUrl(prompt));\n }\n\n /**\n * Log out of every app: ends this app session, then Auth `GET /logout`\n * ends SSO and every app session it issued. `returnUrl` must be allowlisted.\n */\n async logoutEverywhere(\n returnUrl = `${new URL(this.config.returnUrl).origin}/`,\n assign: (url: string) => void = defaultAssign,\n ): Promise<void> {\n await this.logout();\n assign(\n buildLogoutUrl({\n authOrigin: this.config.authOrigin,\n appSlug: this.config.appSlug,\n returnUrl,\n }),\n );\n }\n\n async requestMagicLink(\n email: string,\n intent: \"login\" | \"privat\" = \"login\",\n ): Promise<AuthApiResult<MagicLinkResponse>> {\n return authJson<MagicLinkResponse>(this.fetchFn, this.url(\"/magic-link\"), {\n method: \"POST\",\n body: JSON.stringify({\n email,\n app: this.config.appSlug,\n return_url: this.config.returnUrl,\n intent,\n }),\n });\n }\n\n /** Authenticated `POST /invites`. Auth owns mail + accept. */\n async createInvite(\n input: InviteRequest,\n ): Promise<AuthApiResult<InviteResponse>> {\n return this.request<InviteResponse>(\"/invites\", {\n method: \"POST\",\n body: JSON.stringify({\n email: input.email,\n role: input.role,\n app: input.app ?? this.config.appSlug,\n orgnr: input.orgnr,\n return_url: input.return_url ?? this.config.returnUrl,\n }),\n });\n }\n\n async exchangeCode(\n code: string,\n codeVerifier?: string,\n ): Promise<AuthApiResult<SessionPayload & TokenErrorBody>> {\n const res = await authJson<SessionPayload & TokenErrorBody>(\n this.fetchFn,\n this.url(\"/oauth/token\"),\n {\n method: \"POST\",\n body: JSON.stringify({\n grant_type: \"authorization_code\",\n code,\n app: this.config.appSlug,\n ...(codeVerifier ? { code_verifier: codeVerifier } : {}),\n }),\n },\n );\n if (res.status === 200 && isSessionPayload(res.body)) {\n this.setSession(res.body);\n }\n return res;\n }\n\n /**\n * `/callback?code=…` → tokens. Sends the PKCE verifier from\n * `redirectToLogin()` when there is one (codes from a magic link have none).\n * Throws the callback `error` (e.g. `login_required`) or `missing_code`.\n */\n async handleCallback(codeOrSearch: string): Promise<SessionPayload> {\n const error = readCallbackError(codeOrSearch);\n const verifier = this.pkceStorage.getItem(this.pkceKey) ?? undefined;\n this.pkceStorage.removeItem(this.pkceKey);\n if (error) {\n throw new Error(error);\n }\n const code = readCallbackCode(codeOrSearch);\n if (!code) {\n throw new Error(\"missing_code\");\n }\n const res = await this.exchangeCode(code, verifier);\n if (res.status !== 200 || !isSessionPayload(res.body)) {\n throw new Error(res.body.error ?? \"exchange_failed\");\n }\n return this.current!;\n }\n\n async logout(): Promise<void> {\n const token = this.token;\n if (token) {\n await authJson(this.fetchFn, this.url(\"/logout\"), {\n method: \"POST\",\n token,\n }).catch(() => undefined);\n }\n this.clearSession();\n }\n\n /**\n * Authenticated JSON request with Bearer token, proactive refresh, and a\n * single 401 retry — same shape as the auth console `SessionStore.request`.\n *\n * Clears the stored session only when refresh is known-invalid (expired /\n * revoked refresh token). Network blips and 5xx do not log the user out.\n */\n async request<T>(\n path: string,\n init: RequestInit = {},\n ): Promise<AuthApiResult<T>> {\n const fresh = await this.ensureFreshToken();\n if (!fresh) {\n if (!this.token) {\n return { status: 401, body: { error: \"unauthorized\" } as T };\n }\n // Transient refresh failure — keep session; caller can retry later.\n return { status: 503, body: { error: \"refresh_unavailable\" } as T };\n }\n const first = await authJson<T>(this.fetchFn, this.url(path), {\n ...init,\n token: this.token,\n });\n if (!isUnauthorized(first.status, first.body)) return first;\n const renewed = await this.refreshSessionDetailed();\n if (renewed === \"refreshed\") {\n return authJson<T>(this.fetchFn, this.url(path), {\n ...init,\n token: this.token,\n });\n }\n if (renewed === \"invalid\") {\n this.clearSession();\n }\n return first;\n }\n\n async ensureFreshToken(): Promise<boolean> {\n if (!this.token) return false;\n const expiresAt = accessTokenExpiresAtMs(this.current ?? {});\n if (\n !accessTokenNeedsRefresh(\n expiresAt,\n Date.now(),\n this.config.refreshSkewMs,\n )\n ) {\n return true;\n }\n const outcome = await this.refreshSessionDetailed();\n if (outcome === \"refreshed\") return true;\n if (outcome === \"invalid\") {\n this.clearSession();\n return false;\n }\n // Transient: keep stored session so the caller can retry.\n return false;\n }\n\n async refreshSession(): Promise<boolean> {\n const outcome = await this.refreshSessionDetailed();\n if (outcome === \"refreshed\") return true;\n if (outcome === \"invalid\") {\n this.clearSession();\n }\n return false;\n }\n\n private async refreshSessionDetailed(): Promise<RefreshOutcome> {\n if (this.refreshInFlight) return this.refreshInFlight;\n const run = () => this.doRefresh();\n this.refreshInFlight = (\n this.locks\n ? this.locks.request(`${this.config.storageKey}:refresh`, run)\n : run()\n ).finally(() => {\n this.refreshInFlight = null;\n });\n return this.refreshInFlight;\n }\n\n /**\n * Auth rotates the refresh token on every use and the old one dies at once,\n * so every tab on this origin must use the newest stored token: adopt what\n * another tab stored before refreshing, and after an `invalid_refresh`.\n */\n private async doRefresh(): Promise<RefreshOutcome> {\n const stored = this.loadFromStorage();\n if (stored && stored.refresh_token !== this.current?.refresh_token) {\n this.current = stored;\n this.emit();\n const expiresAt = accessTokenExpiresAtMs(stored);\n if (!accessTokenNeedsRefresh(expiresAt, Date.now(), this.config.refreshSkewMs)) {\n return \"refreshed\";\n }\n }\n const outcome = await this.postRefresh();\n if (outcome !== \"invalid\") return outcome;\n const latest = this.loadFromStorage();\n if (latest && latest.refresh_token !== this.current?.refresh_token) {\n this.current = latest;\n this.emit();\n return \"refreshed\";\n }\n return \"invalid\";\n }\n\n private async postRefresh(): Promise<RefreshOutcome> {\n const refreshToken = this.current?.refresh_token;\n if (!refreshToken) return \"invalid\";\n try {\n const res = await authJson<SessionPayload & TokenErrorBody>(\n this.fetchFn,\n this.url(\"/oauth/token\"),\n {\n method: \"POST\",\n body: JSON.stringify({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n },\n );\n if (res.status === 200 && isSessionPayload(res.body)) {\n this.setSession(res.body);\n return \"refreshed\";\n }\n if (isInvalidRefreshResponse(res.status, res.body)) {\n return \"invalid\";\n }\n return \"transient\";\n } catch {\n // Network error / aborted fetch — do not clear session.\n return \"transient\";\n }\n }\n\n private url(path: string): string {\n return joinAuthUrl(this.config.authOrigin, path);\n }\n\n private loadFromStorage(): SessionPayload | null {\n const raw = readStoredJson<SessionPayload>(\n this.storage,\n this.config.storageKey,\n );\n if (!raw || !isSessionPayload(raw)) return null;\n return withExpiresAt(raw);\n }\n}\n\nexport function createAuthClient(\n config: AuthClientConfig,\n options?: AuthClientOptions,\n): AuthClient {\n return new AuthClient(config, options);\n}\n\nfunction defaultPkceStorage(): SessionStorageLike {\n try {\n if (typeof sessionStorage !== \"undefined\") return sessionStorage;\n } catch {\n // private mode / non-browser\n }\n return createMemoryStorage();\n}\n\nfunction defaultLocks(): LockManagerLike | null {\n const locks = (globalThis as { navigator?: { locks?: LockManagerLike } })\n .navigator?.locks;\n return locks && typeof locks.request === \"function\" ? locks : null;\n}\n\nfunction defaultAssign(url: string): void {\n if (typeof location !== \"undefined\") {\n location.assign(url);\n return;\n }\n throw new Error(`redirectToLogin: no location (${url})`);\n}\n","import { InjectionToken } from \"@angular/core\";\nimport type { ResolvedAuthClientConfig } from \"./config\";\n\nexport const AUTH_CLIENT_CONFIG = new InjectionToken<ResolvedAuthClientConfig>(\n \"AUTH_CLIENT_CONFIG\",\n);\n","import { DestroyRef, Injectable, computed, inject, signal } from \"@angular/core\";\nimport { Router } from \"@angular/router\";\nimport { AuthClient, type RedirectToLoginOptions } from \"./client\";\nimport { AUTH_CLIENT_CONFIG } from \"./tokens\";\nimport type {\n AuthApiResult,\n InviteRequest,\n InviteResponse,\n MagicLinkResponse,\n SessionPayload,\n} from \"./types\";\n\n@Injectable()\nexport class SessionStore {\n private readonly client = inject(AuthClient);\n private readonly router = inject(Router);\n private readonly config = inject(AUTH_CLIENT_CONFIG);\n readonly session = signal<SessionPayload | null>(this.client.getSession());\n readonly token = computed(() => this.session()?.access_token ?? \"\");\n readonly user = computed(() => this.session()?.user ?? null);\n readonly app = computed(() => this.session()?.app ?? null);\n readonly roles = computed(() => this.session()?.roles ?? []);\n readonly permissions = computed(() => this.session()?.permissions ?? []);\n\n constructor() {\n const stop = this.client.onChange((session) => this.session.set(session));\n inject(DestroyRef).onDestroy(stop);\n }\n\n can(permission: string): boolean {\n return this.permissions().includes(permission);\n }\n\n set(session: SessionPayload): void {\n this.session.set(this.client.setSession(session));\n }\n\n clear(): void {\n this.client.clearSession();\n this.session.set(null);\n }\n\n expireToLogin(): void {\n this.clear();\n void this.router.navigateByUrl(this.config.expiredPath ?? \"/login?expired=1\");\n }\n\n async logout(): Promise<void> {\n await this.client.logout();\n this.session.set(null);\n }\n\n loginUrl(): string {\n return this.client.loginUrl();\n }\n\n /** Auth `/authorize`: SSO if signed in on Auth, else the hosted login page. */\n redirectToLogin(options: RedirectToLoginOptions = {}): Promise<void> {\n return this.client.redirectToLogin(options);\n }\n\n /** Ends SSO and every app session it issued, then returns to `returnUrl`. */\n logoutEverywhere(returnUrl?: string): Promise<void> {\n return this.client.logoutEverywhere(returnUrl);\n }\n\n async requestMagicLink(\n email: string,\n intent: \"login\" | \"privat\" = \"login\",\n ): Promise<AuthApiResult<MagicLinkResponse>> {\n return this.client.requestMagicLink(email, intent);\n }\n\n async createInvite(\n input: InviteRequest,\n ): Promise<AuthApiResult<InviteResponse>> {\n const result = await this.client.createInvite(input);\n this.session.set(this.client.getSession());\n return result;\n }\n\n async handleCallback(codeOrSearch: string): Promise<SessionPayload> {\n const session = await this.client.handleCallback(codeOrSearch);\n this.session.set(session);\n return session;\n }\n\n async request<T>(\n path: string,\n init: RequestInit = {},\n ): Promise<AuthApiResult<T>> {\n const result = await this.client.request<T>(path, init);\n this.session.set(this.client.getSession());\n if (result.status === 401 && !this.client.token) {\n this.expireToLogin();\n }\n return result;\n }\n\n async ensureFreshToken(): Promise<boolean> {\n const ok = await this.client.ensureFreshToken();\n this.session.set(this.client.getSession());\n return ok;\n }\n\n async refreshSession(): Promise<boolean> {\n const ok = await this.client.refreshSession();\n this.session.set(this.client.getSession());\n return ok;\n }\n}\n","import { makeEnvironmentProviders, type EnvironmentProviders } from \"@angular/core\";\nimport { AuthClient } from \"./client\";\nimport { resolveAuthClientConfig, type AuthClientConfig } from \"./config\";\nimport { SessionStore } from \"./session\";\nimport { defaultSessionStorage } from \"./storage\";\nimport { AUTH_CLIENT_CONFIG } from \"./tokens\";\n\nexport function provideAuthClient(\n config: AuthClientConfig,\n): EnvironmentProviders {\n const resolved = resolveAuthClientConfig(config);\n return makeEnvironmentProviders([\n { provide: AUTH_CLIENT_CONFIG, useValue: resolved },\n {\n provide: AuthClient,\n useFactory: () =>\n new AuthClient(resolved, { storage: defaultSessionStorage() }),\n },\n SessionStore,\n ]);\n}\n","import { inject } from \"@angular/core\";\nimport { type CanActivateFn, Router } from \"@angular/router\";\nimport { SessionStore } from \"./session\";\n\nexport function requireAuthSession(loginUrl = \"/login\"): CanActivateFn {\n return () => {\n const session = inject(SessionStore);\n const router = inject(Router);\n return session.token() ? true : router.parseUrl(loginUrl);\n };\n}\n","import { Component, input, output } from \"@angular/core\";\n\n/**\n * Placeholder for a shared grant-access dialog.\n * Product apps should keep their own UI in v1 — this is not blocking.\n */\n@Component({\n selector: \"jg-auth-grant-dialog\",\n template: `\n @if (open()) {\n <p class=\"jg-auth-grant-dialog-stub\">\n Grant dialog is not implemented in @byggnode/auth-client v1.\n </p>\n }\n `,\n})\nexport class GrantDialog {\n readonly open = input(false);\n readonly closed = output<void>();\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"byggnode-auth-client.mjs","sources":["../../src/lib/session-expiry.ts","../../src/lib/config.ts","../../src/lib/http.ts","../../src/lib/storage.ts","../../src/lib/types.ts","../../src/lib/pkce.ts","../../src/lib/urls.ts","../../src/lib/client.ts","../../src/lib/tokens.ts","../../src/lib/session.ts","../../src/lib/provide.ts","../../src/lib/guards.ts","../../src/lib/grant-dialog.ts","../../src/byggnode-auth-client.ts"],"sourcesContent":["export const ACCESS_REFRESH_SKEW_MS = 60_000;\n\nexport function jwtExpMs(accessToken: string): number | null {\n const parts = accessToken.split(\".\");\n if (parts.length < 2 || !parts[1]) return null;\n try {\n const raw = parts[1].replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\");\n const pad = raw.length % 4 === 0 ? \"\" : \"=\".repeat(4 - (raw.length % 4));\n const json = atob(raw + pad);\n const exp = (JSON.parse(json) as { exp?: unknown }).exp;\n return typeof exp === \"number\" && Number.isFinite(exp) ? exp * 1000 : null;\n } catch {\n return null;\n }\n}\n\nexport function accessTokenExpiresAtMs(session: {\n access_token?: string;\n expires_at?: number;\n}): number | null {\n if (typeof session.expires_at === \"number\" && Number.isFinite(session.expires_at)) {\n return session.expires_at;\n }\n return jwtExpMs(session.access_token ?? \"\");\n}\n\nexport function accessTokenNeedsRefresh(\n expiresAtMs: number | null,\n now = Date.now(),\n skewMs = ACCESS_REFRESH_SKEW_MS,\n): boolean {\n if (expiresAtMs == null) return false;\n return expiresAtMs - now <= skewMs;\n}\n\nexport function withExpiresAt<\n T extends { access_token: string; expires_in?: number; expires_at?: number },\n>(session: T, now = Date.now()): T & { expires_at?: number } {\n const fromJwt = jwtExpMs(session.access_token);\n const fromTtl =\n typeof session.expires_in === \"number\" && session.expires_in > 0\n ? now + session.expires_in * 1000\n : null;\n const expiresAt = session.expires_at ?? fromJwt ?? fromTtl ?? undefined;\n return expiresAt == null ? session : { ...session, expires_at: expiresAt };\n}\n","import { ACCESS_REFRESH_SKEW_MS } from \"./session-expiry\";\n\nexport type AuthClientConfig = {\n /** IdP origin, e.g. `https://auth.byggnode.no`. Empty string = same origin. */\n authOrigin: string;\n /** Registered app slug sent on magic-link / login redirect / token exchange. */\n appSlug: string;\n /** Allowed callback URL; verify redirects here with `?code=`. */\n returnUrl: string;\n /** Browser storage key (localStorage by default). Default matches the auth console (`auth.session`). */\n storageKey?: string;\n /** Path on the IdP for the hosted login page. Default `/login`. */\n loginPath?: string;\n /** Path on the IdP for the SSO redirect. Default `/authorize`. */\n authorizePath?: string;\n /** Refresh this many ms before access-token expiry. Default 60s. */\n refreshSkewMs?: number;\n /** Router path SessionStore uses after a failed refresh. Default `/login?expired=1`. */\n expiredPath?: string;\n};\n\nexport type ResolvedAuthClientConfig = {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n storageKey: string;\n loginPath: string;\n authorizePath: string;\n refreshSkewMs: number;\n expiredPath: string;\n};\n\nexport function resolveAuthClientConfig(\n config: AuthClientConfig,\n): ResolvedAuthClientConfig {\n const appSlug = config.appSlug.trim();\n const returnUrl = config.returnUrl.trim();\n if (!appSlug) {\n throw new Error(\"provideAuthClient: appSlug is required\");\n }\n if (!returnUrl) {\n throw new Error(\"provideAuthClient: returnUrl is required\");\n }\n return {\n authOrigin: config.authOrigin.replace(/\\/$/, \"\"),\n appSlug,\n returnUrl,\n storageKey: config.storageKey?.trim() || \"auth.session\",\n loginPath: config.loginPath?.trim() || \"/login\",\n authorizePath: config.authorizePath?.trim() || \"/authorize\",\n refreshSkewMs: config.refreshSkewMs ?? ACCESS_REFRESH_SKEW_MS,\n expiredPath: config.expiredPath?.trim() || \"/login?expired=1\",\n };\n}\n","import type { AuthApiResult } from \"./types\";\n\nexport function readErrorCode(body: unknown): string {\n if (!body || typeof body !== \"object\") return \"\";\n const error = (body as { error?: unknown }).error;\n return typeof error === \"string\" ? error : \"\";\n}\n\nexport function isUnauthorized(status: number, body: unknown): boolean {\n if (status === 401) return true;\n return readErrorCode(body) === \"unauthorized\";\n}\n\nexport function jsonHeaders(\n init: RequestInit & { token?: string } = {},\n): Headers {\n const headers = new Headers(init.headers);\n if (init.body && !headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n if (init.token) headers.set(\"authorization\", `Bearer ${init.token}`);\n return headers;\n}\n\nexport async function parseJsonResponse<T>(\n res: Response,\n): Promise<AuthApiResult<T>> {\n const body = (await res.json().catch(() => ({}))) as T;\n return { status: res.status, body };\n}\n\nexport type AuthFetchFn = (\n input: string,\n init?: RequestInit,\n) => Promise<Response>;\n\nexport async function authJson<T>(\n fetchFn: AuthFetchFn,\n url: string,\n init: RequestInit & { token?: string } = {},\n): Promise<AuthApiResult<T>> {\n const { token, ...rest } = init;\n const res = await fetchFn(url, { ...rest, headers: jsonHeaders(init) });\n return parseJsonResponse<T>(res);\n}\n","export type SessionStorageLike = {\n getItem(key: string): string | null;\n setItem(key: string, value: string): void;\n removeItem(key: string): void;\n};\n\nexport function createMemoryStorage(): SessionStorageLike {\n const map = new Map<string, string>();\n return {\n getItem(key) {\n return map.get(key) ?? null;\n },\n setItem(key, value) {\n map.set(key, value);\n },\n removeItem(key) {\n map.delete(key);\n },\n };\n}\n\n/**\n * Prefer localStorage so IdP sessions survive new tabs and browser restarts.\n * Fall back to in-memory storage when localStorage is unavailable (private\n * mode / non-browser); sessionStorage is a last resort if localStorage throws\n * but sessionStorage works.\n */\n/** One-shot: copy auth.session from sessionStorage → localStorage (cutover). */\nfunction migrateSessionKeyToLocal(key = \"auth.session\"): void {\n try {\n if (typeof localStorage === \"undefined\" || typeof sessionStorage === \"undefined\") return;\n if (localStorage.getItem(key)) return;\n const raw = sessionStorage.getItem(key);\n if (!raw) return;\n localStorage.setItem(key, raw);\n sessionStorage.removeItem(key);\n } catch {\n // ignore quota / private mode\n }\n}\n\nexport function defaultSessionStorage(): SessionStorageLike {\n try {\n if (typeof localStorage !== \"undefined\") {\n migrateSessionKeyToLocal();\n return localStorage;\n }\n } catch {\n // private mode / non-browser\n }\n try {\n if (typeof sessionStorage !== \"undefined\") return sessionStorage;\n } catch {\n // private mode / non-browser\n }\n return createMemoryStorage();\n}\n\nexport function readStoredJson<T>(\n storage: SessionStorageLike,\n key: string,\n): T | null {\n try {\n const raw = storage.getItem(key);\n if (!raw) return null;\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n","export type AuthUser = {\n id: string;\n email: string;\n};\n\nexport type AppInfo = {\n slug: string;\n name: string;\n active?: boolean;\n allowed_origins?: string[];\n redirect_uris?: string[];\n};\n\nexport type RoleScope = {\n role: string;\n orgnr: string | null;\n};\n\nexport type SessionPayload = {\n access_token: string;\n refresh_token: string;\n token_type?: string;\n expires_in?: number;\n expires_at?: number;\n session_id?: string;\n user: AuthUser;\n app: { slug: string; name: string };\n roles: string[];\n permissions: string[];\n scopes: RoleScope[];\n};\n\nexport type AuthApiResult<T> = {\n status: number;\n body: T;\n};\n\nexport type MagicLinkResponse = {\n ok?: boolean;\n error?: string;\n dev_token?: string;\n dev_code?: string;\n};\n\nexport type InviteRequest = {\n email: string;\n role: string;\n app?: string;\n orgnr?: string;\n return_url?: string;\n};\n\nexport type InviteResponse = {\n ok?: boolean;\n error?: string;\n invite?: {\n id: string;\n email: string;\n role: string;\n app: string;\n orgnr: string | null;\n status?: string;\n expires_at: string;\n };\n dev_token?: string;\n};\n\nexport type TokenErrorBody = {\n error?: string;\n};\n\nexport type RoleRow = {\n slug: string;\n name: string;\n description?: string | null;\n permissions: string[];\n};\n\nexport function isSessionPayload(value: unknown): value is SessionPayload {\n if (!value || typeof value !== \"object\") return false;\n const rec = value as Partial<SessionPayload>;\n return (\n typeof rec.access_token === \"string\" &&\n rec.access_token.length > 0 &&\n typeof rec.refresh_token === \"string\" &&\n !!rec.user &&\n typeof rec.user.id === \"string\" &&\n typeof rec.user.email === \"string\" &&\n !!rec.app &&\n typeof rec.app.slug === \"string\" &&\n Array.isArray(rec.roles) &&\n Array.isArray(rec.permissions)\n );\n}\n","function base64url(bytes: Uint8Array): string {\n let binary = \"\";\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary).replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/, \"\");\n}\n\n/** RFC 7636 S256 pair: 43-char verifier, base64url(sha256(verifier)) challenge. */\nexport async function createPkcePair(): Promise<{\n verifier: string;\n challenge: string;\n}> {\n const verifier = base64url(crypto.getRandomValues(new Uint8Array(32)));\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(verifier),\n );\n return { verifier, challenge: base64url(new Uint8Array(digest)) };\n}\n","export function joinAuthUrl(origin: string, path: string): string {\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n if (!origin) return normalizedPath;\n return `${origin.replace(/\\/$/, \"\")}${normalizedPath}`;\n}\n\nexport function isHttpUrl(value: string): boolean {\n try {\n const url = new URL(value);\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n } catch {\n return false;\n }\n}\n\nexport function resolveReturnUrl(\n requested: string | null | undefined,\n fallback: string,\n): string {\n if (requested && isHttpUrl(requested)) return requested;\n return fallback;\n}\n\nexport function readCallbackCode(searchOrUrl: string): string | null {\n const raw = searchOrUrl.trim();\n if (!raw) return null;\n try {\n if (raw.includes(\"://\") || raw.startsWith(\"/\") || raw.startsWith(\"?\")) {\n const url = raw.includes(\"://\")\n ? new URL(raw)\n : new URL(raw, \"http://auth.local\");\n return url.searchParams.get(\"code\");\n }\n } catch {\n // treat as a bare code below\n }\n if (raw.includes(\"=\")) {\n return new URLSearchParams(raw.startsWith(\"?\") ? raw.slice(1) : raw).get(\n \"code\",\n );\n }\n return raw;\n}\n\n/** `error` on the callback URL, e.g. `login_required` after `prompt=none`. */\nexport function readCallbackError(searchOrUrl: string): string | null {\n const raw = searchOrUrl.trim();\n if (!raw.includes(\"=\")) return null;\n try {\n const url = raw.includes(\"://\") ? new URL(raw) : new URL(raw, \"http://auth.local\");\n return (\n url.searchParams.get(\"error\") ??\n new URLSearchParams(raw.startsWith(\"?\") ? raw.slice(1) : raw).get(\"error\")\n );\n } catch {\n return null;\n }\n}\n\nexport function buildAuthorizeUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n codeChallenge: string;\n authorizePath?: string;\n prompt?: \"none\";\n}): string {\n const url = new URL(\n joinAuthUrl(opts.authOrigin, opts.authorizePath ?? \"/authorize\"),\n \"http://auth.local\",\n );\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n url.searchParams.set(\"code_challenge\", opts.codeChallenge);\n url.searchParams.set(\"code_challenge_method\", \"S256\");\n if (opts.prompt) url.searchParams.set(\"prompt\", opts.prompt);\n return opts.authOrigin ? url.toString() : `${url.pathname}${url.search}`;\n}\n\n/** Auth `GET /logout`: ends SSO and every app session it issued. */\nexport function buildLogoutUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n}): string {\n const url = new URL(joinAuthUrl(opts.authOrigin, \"/logout\"), \"http://auth.local\");\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n return opts.authOrigin ? url.toString() : `${url.pathname}${url.search}`;\n}\n\nexport function buildLoginUrl(opts: {\n authOrigin: string;\n appSlug: string;\n returnUrl: string;\n loginPath?: string;\n}): string {\n const path = joinAuthUrl(opts.authOrigin, opts.loginPath ?? \"/login\");\n const url = path.includes(\"://\")\n ? new URL(path)\n : new URL(path, \"http://auth.local\");\n url.searchParams.set(\"app\", opts.appSlug);\n url.searchParams.set(\"return_url\", opts.returnUrl);\n if (path.includes(\"://\")) return url.toString();\n return `${url.pathname}${url.search}`;\n}\n","import {\n resolveAuthClientConfig,\n type AuthClientConfig,\n type ResolvedAuthClientConfig,\n} from \"./config\";\nimport {\n authJson,\n isUnauthorized,\n readErrorCode,\n type AuthFetchFn,\n} from \"./http\";\nimport {\n accessTokenExpiresAtMs,\n accessTokenNeedsRefresh,\n withExpiresAt,\n} from \"./session-expiry\";\nimport {\n createMemoryStorage,\n defaultSessionStorage,\n readStoredJson,\n type SessionStorageLike,\n} from \"./storage\";\nimport {\n isSessionPayload,\n type AuthApiResult,\n type InviteRequest,\n type InviteResponse,\n type MagicLinkResponse,\n type SessionPayload,\n type TokenErrorBody,\n} from \"./types\";\nimport { createPkcePair } from \"./pkce\";\nimport {\n buildAuthorizeUrl,\n buildLoginUrl,\n buildLogoutUrl,\n joinAuthUrl,\n readCallbackCode,\n readCallbackError,\n} from \"./urls\";\n\n/** The subset of the Web Locks API the client uses. */\nexport type LockManagerLike = {\n request<T>(name: string, callback: () => Promise<T>): Promise<T>;\n};\n\nexport type AuthClientOptions = {\n storage?: SessionStorageLike;\n /** Holds the PKCE verifier between /authorize and /callback. Default sessionStorage. */\n pkceStorage?: SessionStorageLike;\n fetch?: AuthFetchFn;\n /** Serializes refresh across tabs. Default `navigator.locks` when available. */\n locks?: LockManagerLike | null;\n};\n\nexport type RedirectToLoginOptions = {\n /** `none`: come back with `?error=login_required` instead of showing the login page. */\n prompt?: \"none\";\n assign?: (url: string) => void;\n};\n\n/** Outcome of a refresh_token grant attempt. */\ntype RefreshOutcome = \"refreshed\" | \"invalid\" | \"transient\";\n\nconst INVALID_REFRESH_ERRORS = new Set([\n \"invalid_refresh\",\n \"refresh_expired\",\n \"refresh_token_required\",\n \"invalid_grant\",\n]);\n\nfunction isInvalidRefreshResponse(status: number, body: unknown): boolean {\n if (status === 401) return true;\n if (status !== 400) return false;\n const code = readErrorCode(body);\n return INVALID_REFRESH_ERRORS.has(code);\n}\n\nexport class AuthClient {\n readonly config: ResolvedAuthClientConfig;\n private readonly storage: SessionStorageLike;\n private readonly pkceStorage: SessionStorageLike;\n private readonly fetchFn: AuthFetchFn;\n private readonly locks: LockManagerLike | null;\n private readonly listeners = new Set<(session: SessionPayload | null) => void>();\n private current: SessionPayload | null;\n private refreshInFlight: Promise<RefreshOutcome> | null = null;\n\n constructor(config: AuthClientConfig, options: AuthClientOptions = {}) {\n this.config = resolveAuthClientConfig(config);\n this.storage = options.storage ?? defaultSessionStorage();\n this.pkceStorage = options.pkceStorage ?? defaultPkceStorage();\n this.fetchFn = options.fetch ?? fetch;\n this.locks =\n options.locks === undefined ? defaultLocks() : options.locks;\n this.current = this.loadFromStorage();\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"storage\", (event) => {\n if (event.key === this.config.storageKey || event.key === null) {\n this.reloadFromStorage();\n }\n });\n }\n }\n\n /** Called whenever the session changes, including from another tab. */\n onChange(listener: (session: SessionPayload | null) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n /** Adopt what another tab (or app on this origin) stored. */\n reloadFromStorage(): SessionPayload | null {\n this.current = this.loadFromStorage();\n this.emit();\n return this.current;\n }\n\n private emit(): void {\n for (const listener of this.listeners) listener(this.current);\n }\n\n private get pkceKey(): string {\n return `${this.config.storageKey}.pkce`;\n }\n\n getSession(): SessionPayload | null {\n return this.current;\n }\n\n get token(): string {\n return this.current?.access_token ?? \"\";\n }\n\n get user(): SessionPayload[\"user\"] | null {\n return this.current?.user ?? null;\n }\n\n get app(): SessionPayload[\"app\"] | null {\n return this.current?.app ?? null;\n }\n\n get roles(): string[] {\n return this.current?.roles ?? [];\n }\n\n get permissions(): string[] {\n return this.current?.permissions ?? [];\n }\n\n can(permission: string): boolean {\n return this.permissions.includes(permission);\n }\n\n setSession(session: SessionPayload): SessionPayload {\n const next = withExpiresAt(session);\n this.current = next;\n this.storage.setItem(this.config.storageKey, JSON.stringify(next));\n this.emit();\n return next;\n }\n\n clearSession(): void {\n this.current = null;\n this.storage.removeItem(this.config.storageKey);\n this.emit();\n }\n\n /** Hosted login page without SSO (`app` + `return_url`). */\n loginUrl(): string {\n return buildLoginUrl(this.config);\n }\n\n /**\n * Auth `GET /authorize` with a fresh PKCE pair. Signed in on Auth already:\n * straight back with a code. Otherwise the hosted login page.\n */\n async authorizeUrl(prompt?: \"none\"): Promise<string> {\n const { verifier, challenge } = await createPkcePair();\n this.pkceStorage.setItem(this.pkceKey, verifier);\n return buildAuthorizeUrl({\n authOrigin: this.config.authOrigin,\n appSlug: this.config.appSlug,\n returnUrl: this.config.returnUrl,\n authorizePath: this.config.authorizePath,\n codeChallenge: challenge,\n prompt,\n });\n }\n\n /** Send the browser through Auth `/authorize` (SSO across app domains). */\n async redirectToLogin(\n options: RedirectToLoginOptions | ((url: string) => void) = {},\n ): Promise<void> {\n const { prompt, assign = defaultAssign } =\n typeof options === \"function\" ? { assign: options } : options;\n assign(await this.authorizeUrl(prompt));\n }\n\n /**\n * Log out of every app: ends this app session, then Auth `GET /logout`\n * ends SSO and every app session it issued. `returnUrl` must be allowlisted.\n */\n async logoutEverywhere(\n returnUrl = `${new URL(this.config.returnUrl).origin}/`,\n assign: (url: string) => void = defaultAssign,\n ): Promise<void> {\n await this.logout();\n assign(\n buildLogoutUrl({\n authOrigin: this.config.authOrigin,\n appSlug: this.config.appSlug,\n returnUrl,\n }),\n );\n }\n\n async requestMagicLink(\n email: string,\n intent: \"login\" | \"privat\" = \"login\",\n ): Promise<AuthApiResult<MagicLinkResponse>> {\n return authJson<MagicLinkResponse>(this.fetchFn, this.url(\"/magic-link\"), {\n method: \"POST\",\n body: JSON.stringify({\n email,\n app: this.config.appSlug,\n return_url: this.config.returnUrl,\n intent,\n }),\n });\n }\n\n /**\n * The 6-digit code from the mail `requestMagicLink()` sent, typed in the\n * app's own form. Logs in without leaving the app (no SSO cookie).\n */\n async loginWithCode(\n email: string,\n code: string,\n ): Promise<AuthApiResult<SessionPayload & TokenErrorBody>> {\n const res = await authJson<{ code?: string; error?: string }>(\n this.fetchFn,\n this.url(\"/magic-link/code\"),\n {\n method: \"POST\",\n body: JSON.stringify({ email, app: this.config.appSlug, code }),\n },\n );\n if (res.status !== 200 || !res.body.code) {\n const body = { error: res.body.error ?? \"invalid_code\" };\n return { status: res.status, body: body as SessionPayload & TokenErrorBody };\n }\n return this.exchangeCode(res.body.code);\n }\n\n /** Authenticated `POST /invites`. Auth owns mail + accept. */\n async createInvite(\n input: InviteRequest,\n ): Promise<AuthApiResult<InviteResponse>> {\n return this.request<InviteResponse>(\"/invites\", {\n method: \"POST\",\n body: JSON.stringify({\n email: input.email,\n role: input.role,\n app: input.app ?? this.config.appSlug,\n orgnr: input.orgnr,\n return_url: input.return_url ?? this.config.returnUrl,\n }),\n });\n }\n\n async exchangeCode(\n code: string,\n codeVerifier?: string,\n ): Promise<AuthApiResult<SessionPayload & TokenErrorBody>> {\n const res = await authJson<SessionPayload & TokenErrorBody>(\n this.fetchFn,\n this.url(\"/oauth/token\"),\n {\n method: \"POST\",\n body: JSON.stringify({\n grant_type: \"authorization_code\",\n code,\n app: this.config.appSlug,\n ...(codeVerifier ? { code_verifier: codeVerifier } : {}),\n }),\n },\n );\n if (res.status === 200 && isSessionPayload(res.body)) {\n this.setSession(res.body);\n }\n return res;\n }\n\n /**\n * `/callback?code=…` → tokens. Sends the PKCE verifier from\n * `redirectToLogin()` when there is one (codes from a magic link have none).\n * Throws the callback `error` (e.g. `login_required`) or `missing_code`.\n */\n async handleCallback(codeOrSearch: string): Promise<SessionPayload> {\n const error = readCallbackError(codeOrSearch);\n const verifier = this.pkceStorage.getItem(this.pkceKey) ?? undefined;\n this.pkceStorage.removeItem(this.pkceKey);\n if (error) {\n throw new Error(error);\n }\n const code = readCallbackCode(codeOrSearch);\n if (!code) {\n throw new Error(\"missing_code\");\n }\n const res = await this.exchangeCode(code, verifier);\n if (res.status !== 200 || !isSessionPayload(res.body)) {\n throw new Error(res.body.error ?? \"exchange_failed\");\n }\n return this.current!;\n }\n\n async logout(): Promise<void> {\n const token = this.token;\n if (token) {\n await authJson(this.fetchFn, this.url(\"/logout\"), {\n method: \"POST\",\n token,\n }).catch(() => undefined);\n }\n this.clearSession();\n }\n\n /**\n * Authenticated JSON request with Bearer token, proactive refresh, and a\n * single 401 retry — same shape as the auth console `SessionStore.request`.\n *\n * Clears the stored session only when refresh is known-invalid (expired /\n * revoked refresh token). Network blips and 5xx do not log the user out.\n */\n async request<T>(\n path: string,\n init: RequestInit = {},\n ): Promise<AuthApiResult<T>> {\n const fresh = await this.ensureFreshToken();\n if (!fresh) {\n if (!this.token) {\n return { status: 401, body: { error: \"unauthorized\" } as T };\n }\n // Transient refresh failure — keep session; caller can retry later.\n return { status: 503, body: { error: \"refresh_unavailable\" } as T };\n }\n const first = await authJson<T>(this.fetchFn, this.url(path), {\n ...init,\n token: this.token,\n });\n if (!isUnauthorized(first.status, first.body)) return first;\n const renewed = await this.refreshSessionDetailed();\n if (renewed === \"refreshed\") {\n return authJson<T>(this.fetchFn, this.url(path), {\n ...init,\n token: this.token,\n });\n }\n if (renewed === \"invalid\") {\n this.clearSession();\n }\n return first;\n }\n\n async ensureFreshToken(): Promise<boolean> {\n if (!this.token) return false;\n const expiresAt = accessTokenExpiresAtMs(this.current ?? {});\n if (\n !accessTokenNeedsRefresh(\n expiresAt,\n Date.now(),\n this.config.refreshSkewMs,\n )\n ) {\n return true;\n }\n const outcome = await this.refreshSessionDetailed();\n if (outcome === \"refreshed\") return true;\n if (outcome === \"invalid\") {\n this.clearSession();\n return false;\n }\n // Transient: keep stored session so the caller can retry.\n return false;\n }\n\n async refreshSession(): Promise<boolean> {\n const outcome = await this.refreshSessionDetailed();\n if (outcome === \"refreshed\") return true;\n if (outcome === \"invalid\") {\n this.clearSession();\n }\n return false;\n }\n\n private async refreshSessionDetailed(): Promise<RefreshOutcome> {\n if (this.refreshInFlight) return this.refreshInFlight;\n const run = () => this.doRefresh();\n this.refreshInFlight = (\n this.locks\n ? this.locks.request(`${this.config.storageKey}:refresh`, run)\n : run()\n ).finally(() => {\n this.refreshInFlight = null;\n });\n return this.refreshInFlight;\n }\n\n /**\n * Auth rotates the refresh token on every use and the old one dies at once,\n * so every tab on this origin must use the newest stored token: adopt what\n * another tab stored before refreshing, and after an `invalid_refresh`.\n */\n private async doRefresh(): Promise<RefreshOutcome> {\n const stored = this.loadFromStorage();\n if (stored && stored.refresh_token !== this.current?.refresh_token) {\n this.current = stored;\n this.emit();\n const expiresAt = accessTokenExpiresAtMs(stored);\n if (!accessTokenNeedsRefresh(expiresAt, Date.now(), this.config.refreshSkewMs)) {\n return \"refreshed\";\n }\n }\n const outcome = await this.postRefresh();\n if (outcome !== \"invalid\") return outcome;\n const latest = this.loadFromStorage();\n if (latest && latest.refresh_token !== this.current?.refresh_token) {\n this.current = latest;\n this.emit();\n return \"refreshed\";\n }\n return \"invalid\";\n }\n\n private async postRefresh(): Promise<RefreshOutcome> {\n const refreshToken = this.current?.refresh_token;\n if (!refreshToken) return \"invalid\";\n try {\n const res = await authJson<SessionPayload & TokenErrorBody>(\n this.fetchFn,\n this.url(\"/oauth/token\"),\n {\n method: \"POST\",\n body: JSON.stringify({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n },\n );\n if (res.status === 200 && isSessionPayload(res.body)) {\n this.setSession(res.body);\n return \"refreshed\";\n }\n if (isInvalidRefreshResponse(res.status, res.body)) {\n return \"invalid\";\n }\n return \"transient\";\n } catch {\n // Network error / aborted fetch — do not clear session.\n return \"transient\";\n }\n }\n\n private url(path: string): string {\n return joinAuthUrl(this.config.authOrigin, path);\n }\n\n private loadFromStorage(): SessionPayload | null {\n const raw = readStoredJson<SessionPayload>(\n this.storage,\n this.config.storageKey,\n );\n if (!raw || !isSessionPayload(raw)) return null;\n return withExpiresAt(raw);\n }\n}\n\nexport function createAuthClient(\n config: AuthClientConfig,\n options?: AuthClientOptions,\n): AuthClient {\n return new AuthClient(config, options);\n}\n\nfunction defaultPkceStorage(): SessionStorageLike {\n try {\n if (typeof sessionStorage !== \"undefined\") return sessionStorage;\n } catch {\n // private mode / non-browser\n }\n return createMemoryStorage();\n}\n\nfunction defaultLocks(): LockManagerLike | null {\n const locks = (globalThis as { navigator?: { locks?: LockManagerLike } })\n .navigator?.locks;\n return locks && typeof locks.request === \"function\" ? locks : null;\n}\n\nfunction defaultAssign(url: string): void {\n if (typeof location !== \"undefined\") {\n location.assign(url);\n return;\n }\n throw new Error(`redirectToLogin: no location (${url})`);\n}\n","import { InjectionToken } from \"@angular/core\";\nimport type { ResolvedAuthClientConfig } from \"./config\";\n\nexport const AUTH_CLIENT_CONFIG = new InjectionToken<ResolvedAuthClientConfig>(\n \"AUTH_CLIENT_CONFIG\",\n);\n","import { DestroyRef, Injectable, computed, inject, signal } from \"@angular/core\";\nimport { Router } from \"@angular/router\";\nimport { AuthClient, type RedirectToLoginOptions } from \"./client\";\nimport { AUTH_CLIENT_CONFIG } from \"./tokens\";\nimport type {\n AuthApiResult,\n InviteRequest,\n InviteResponse,\n MagicLinkResponse,\n SessionPayload,\n TokenErrorBody,\n} from \"./types\";\n\n@Injectable()\nexport class SessionStore {\n private readonly client = inject(AuthClient);\n private readonly router = inject(Router);\n private readonly config = inject(AUTH_CLIENT_CONFIG);\n readonly session = signal<SessionPayload | null>(this.client.getSession());\n readonly token = computed(() => this.session()?.access_token ?? \"\");\n readonly user = computed(() => this.session()?.user ?? null);\n readonly app = computed(() => this.session()?.app ?? null);\n readonly roles = computed(() => this.session()?.roles ?? []);\n readonly permissions = computed(() => this.session()?.permissions ?? []);\n\n constructor() {\n const stop = this.client.onChange((session) => this.session.set(session));\n inject(DestroyRef).onDestroy(stop);\n }\n\n can(permission: string): boolean {\n return this.permissions().includes(permission);\n }\n\n set(session: SessionPayload): void {\n this.session.set(this.client.setSession(session));\n }\n\n clear(): void {\n this.client.clearSession();\n this.session.set(null);\n }\n\n expireToLogin(): void {\n this.clear();\n void this.router.navigateByUrl(this.config.expiredPath ?? \"/login?expired=1\");\n }\n\n async logout(): Promise<void> {\n await this.client.logout();\n this.session.set(null);\n }\n\n loginUrl(): string {\n return this.client.loginUrl();\n }\n\n /** Auth `/authorize`: SSO if signed in on Auth, else the hosted login page. */\n redirectToLogin(options: RedirectToLoginOptions = {}): Promise<void> {\n return this.client.redirectToLogin(options);\n }\n\n /** Ends SSO and every app session it issued, then returns to `returnUrl`. */\n logoutEverywhere(returnUrl?: string): Promise<void> {\n return this.client.logoutEverywhere(returnUrl);\n }\n\n async requestMagicLink(\n email: string,\n intent: \"login\" | \"privat\" = \"login\",\n ): Promise<AuthApiResult<MagicLinkResponse>> {\n return this.client.requestMagicLink(email, intent);\n }\n\n /** The 6-digit code from that mail, typed in the app's own form. */\n async loginWithCode(\n email: string,\n code: string,\n ): Promise<AuthApiResult<SessionPayload & TokenErrorBody>> {\n const result = await this.client.loginWithCode(email, code);\n this.session.set(this.client.getSession());\n return result;\n }\n\n async createInvite(\n input: InviteRequest,\n ): Promise<AuthApiResult<InviteResponse>> {\n const result = await this.client.createInvite(input);\n this.session.set(this.client.getSession());\n return result;\n }\n\n async handleCallback(codeOrSearch: string): Promise<SessionPayload> {\n const session = await this.client.handleCallback(codeOrSearch);\n this.session.set(session);\n return session;\n }\n\n async request<T>(\n path: string,\n init: RequestInit = {},\n ): Promise<AuthApiResult<T>> {\n const result = await this.client.request<T>(path, init);\n this.session.set(this.client.getSession());\n if (result.status === 401 && !this.client.token) {\n this.expireToLogin();\n }\n return result;\n }\n\n async ensureFreshToken(): Promise<boolean> {\n const ok = await this.client.ensureFreshToken();\n this.session.set(this.client.getSession());\n return ok;\n }\n\n async refreshSession(): Promise<boolean> {\n const ok = await this.client.refreshSession();\n this.session.set(this.client.getSession());\n return ok;\n }\n}\n","import { makeEnvironmentProviders, type EnvironmentProviders } from \"@angular/core\";\nimport { AuthClient } from \"./client\";\nimport { resolveAuthClientConfig, type AuthClientConfig } from \"./config\";\nimport { SessionStore } from \"./session\";\nimport { defaultSessionStorage } from \"./storage\";\nimport { AUTH_CLIENT_CONFIG } from \"./tokens\";\n\nexport function provideAuthClient(\n config: AuthClientConfig,\n): EnvironmentProviders {\n const resolved = resolveAuthClientConfig(config);\n return makeEnvironmentProviders([\n { provide: AUTH_CLIENT_CONFIG, useValue: resolved },\n {\n provide: AuthClient,\n useFactory: () =>\n new AuthClient(resolved, { storage: defaultSessionStorage() }),\n },\n SessionStore,\n ]);\n}\n","import { inject } from \"@angular/core\";\nimport { type CanActivateFn, Router } from \"@angular/router\";\nimport { SessionStore } from \"./session\";\n\nexport function requireAuthSession(loginUrl = \"/login\"): CanActivateFn {\n return () => {\n const session = inject(SessionStore);\n const router = inject(Router);\n return session.token() ? true : router.parseUrl(loginUrl);\n };\n}\n","import { Component, input, output } from \"@angular/core\";\n\n/**\n * Placeholder for a shared grant-access dialog.\n * Product apps should keep their own UI in v1 — this is not blocking.\n */\n@Component({\n selector: \"jg-auth-grant-dialog\",\n template: `\n @if (open()) {\n <p class=\"jg-auth-grant-dialog-stub\">\n Grant dialog is not implemented in @byggnode/auth-client v1.\n </p>\n }\n `,\n})\nexport class GrantDialog {\n readonly open = input(false);\n readonly closed = output<void>();\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byggnode/auth-client",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "Thin Angular client for the Byggnode central auth IdP.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -76,6 +76,7 @@ type MagicLinkResponse = {
76
76
  ok?: boolean;
77
77
  error?: string;
78
78
  dev_token?: string;
79
+ dev_code?: string;
79
80
  };
80
81
  type InviteRequest = {
81
82
  email: string;
@@ -186,6 +187,11 @@ declare class AuthClient {
186
187
  */
187
188
  logoutEverywhere(returnUrl?: string, assign?: (url: string) => void): Promise<void>;
188
189
  requestMagicLink(email: string, intent?: "login" | "privat"): Promise<AuthApiResult<MagicLinkResponse>>;
190
+ /**
191
+ * The 6-digit code from the mail `requestMagicLink()` sent, typed in the
192
+ * app's own form. Logs in without leaving the app (no SSO cookie).
193
+ */
194
+ loginWithCode(email: string, code: string): Promise<AuthApiResult<SessionPayload & TokenErrorBody>>;
189
195
  /** Authenticated `POST /invites`. Auth owns mail + accept. */
190
196
  createInvite(input: InviteRequest): Promise<AuthApiResult<InviteResponse>>;
191
197
  exchangeCode(code: string, codeVerifier?: string): Promise<AuthApiResult<SessionPayload & TokenErrorBody>>;
@@ -244,6 +250,8 @@ declare class SessionStore {
244
250
  /** Ends SSO and every app session it issued, then returns to `returnUrl`. */
245
251
  logoutEverywhere(returnUrl?: string): Promise<void>;
246
252
  requestMagicLink(email: string, intent?: "login" | "privat"): Promise<AuthApiResult<MagicLinkResponse>>;
253
+ /** The 6-digit code from that mail, typed in the app's own form. */
254
+ loginWithCode(email: string, code: string): Promise<AuthApiResult<SessionPayload & TokenErrorBody>>;
247
255
  createInvite(input: InviteRequest): Promise<AuthApiResult<InviteResponse>>;
248
256
  handleCallback(codeOrSearch: string): Promise<SessionPayload>;
249
257
  request<T>(path: string, init?: RequestInit): Promise<AuthApiResult<T>>;