@synqauth/js
Synq's framework-agnostic client: sign-in and sessions in the browser, the account API, and token and webhook verification on your server.
@synqauth/js
AccountApiKey
Type. One of the person's API keys for the brand's APIs: never the key itself.
type AccountApiKey = Schemas['UserApiKey'];AccountApiKeyCreate
Type. What apiKeys.create() takes: the API's identifier, a name, its scopes, and an expiry if any.
type AccountApiKeyCreate = Schemas['UserApiKeyCreate'];accountApiUrl
Function. The account API's URL for a brand: the resource its access tokens are for.
function accountApiUrl(issuer: string | URL): stringAccountClient
Interface. The brand's account API for the signed-in person, as createAccountClient makes it: every call answers { data, error }.
interface AccountClient {
me: (options?: ReadOptions) => Promise<AccountResult<AccountProfile>>;
user: {
update: (changes: AccountProfileUpdate, options?: ChangeOptions) => Promise<AccountResult<AccountProfile>>;
metadata: (options?: ReadOptions) => Promise<AccountResult<Record<string, unknown>>>;
usernameAvailable: (username: string, options?: ReadOptions) => Promise<AccountResult<AccountUsernameAvailability>>;
};
wallets: {
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountWallet[]>>;
update: (wallet: string, changes: AccountWalletUpdate, options?: ChangeOptions) => Promise<AccountResult<AccountWallet>>;
remove: (wallet: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
accounts: {
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountIdentity[]>>;
link: (method: LinkMethod, options?: ChangeOptions) => Promise<AccountResult<AccountLinkRequest>>;
unlink: (identity: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
sessions: {
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountSession[]>>;
revoke: (session: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
passkeys: {
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountPasskey[]>>;
registrationOptions: (options?: ChangeOptions) => Promise<AccountResult<Record<string, unknown>>>;
register: (credential: Record<string, unknown>, options?: ChangeOptions) => Promise<AccountResult<AccountPasskey>>;
remove: (passkey: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
consents: {
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountConsent[]>>;
withdraw: (consent: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
apiKeys: {
apis: (options?: ReadOptions) => Promise<AccountResult<readonly AccountKeyableApi[]>>;
list: (options?: ReadOptions) => Promise<AccountResult<readonly AccountApiKey[]>>;
create: (input: AccountApiKeyCreate, options?: ChangeOptions) => Promise<AccountResult<AccountNewApiKey>>;
revoke: (key: string, options?: ChangeOptions) => Promise<AccountResult<null>>;
};
activity: (options?: ReadOptions) => Promise<AccountResult<readonly AccountSignIn[]>>;
deletion: {
schedule: (options?: ChangeOptions) => Promise<AccountResult<unknown>>;
cancel: (options?: ChangeOptions) => Promise<AccountResult<unknown>>;
};
}AccountClientOptions
Interface. What createAccountClient takes.
interface AccountClientOptions {
issuer: string | URL;
accessToken: () => string | Promise<string>;
fetch?: typeof fetch;
}AccountComponents
Interface. The account API's schemas, generated from its OpenAPI document.
type AccountComponents // generated from the API's OpenAPI document: see the API referenceAccountConsent
Type. What the person allowed an app outside the brand's own to do.
type AccountConsent = Schemas['Consent'];AccountIdentity
Type. One of the person's ways to sign in: a wallet, an email address or a provider's account.
type AccountIdentity = Schemas['Identity'];AccountKeyableApi
Type. An API the person may make keys for, with the scopes it defines.
type AccountKeyableApi = Schemas['KeyableApi'];AccountLinkRequest
Type. A link request: the sign-in that adds a way in carries its authorization_params.
type AccountLinkRequest = Schemas['LinkRequest'];AccountNewApiKey
Type. A new API key: key is the key itself, in this answer only.
type AccountNewApiKey = Schemas['NewUserApiKey'];AccountOperations
Type. The account API's operations, generated from its OpenAPI document.
type AccountOperations // generated from the API's OpenAPI document: see the API referenceAccountPasskey
Type. One of the person's passkeys.
type AccountPasskey = Schemas['Passkey'];AccountPaths
Interface. The account API's paths, generated from its OpenAPI document.
type AccountPaths // generated from the API's OpenAPI document: see the API referenceAccountProfile
Type. The signed-in person's profile, as the account API answers it.
type AccountProfile = Schemas['Profile'];AccountProfileUpdate
Type. What user.update() may change: only the fields given.
type AccountProfileUpdate = Schemas['ProfileUpdate'];AccountResult
Type. A call's outcome: its data, or the SynqError it failed with (branch on error.code).
type AccountResult<T> = {
readonly data: T;
readonly error: null;
} | {
readonly data: null;
readonly error: SynqError;
};AccountSession
Type. One of the person's sessions at the brand; current marks the one the call came from.
type AccountSession = Schemas['Session'];AccountSignIn
Type. One recent sign-in: when, how and to which app.
type AccountSignIn = Schemas['SignIn'];AccountUsernameAvailability
Type. Whether a username is free for the person to take, and why not.
type AccountUsernameAvailability = Schemas['UsernameAvailability'];AccountWallet
Type. One of the person's wallets.
type AccountWallet = Schemas['Wallet'];AccountWalletUpdate
Type. What wallets.update() may change: the label, or making it primary.
type AccountWalletUpdate = Schemas['WalletUpdate'];AuthorizationUrlOptions
Interface. What to ask for when sending someone to sign in.
interface AuthorizationUrlOptions {
method?: string;
loginHint?: string;
prompt?: 'none' | 'login' | 'consent' | 'select_account' | 'create';
maxAge?: number;
scope?: string;
resource?: string;
additionalResources?: readonly string[];
params?: Readonly<Record<string, string>>;
pushed?: boolean;
acr?: {
readonly values: readonly string[];
readonly essential?: boolean;
};
}browserLocalStorage
Function. The browser's localStorage, which every tab of the app's origin shares.
Where a sign-in's transaction goes by default in a browser: a magic link
or an email's link opens a new tab, which finishes the sign-in and comes
back to the app there, so the tab that started it can't be the only one
that knows it. Each transaction is kept under its own state, for an hour
at most, deleted when it finishes, and swept away when stale. The price:
any script on the app's origin can read a transaction meanwhile (its PKCE
verifier and nonce, useless without the code Synq sends to the app's own
redirect URI), as it can read anything else the app keeps. As the
session's store it keeps the access and ID tokens only, never the refresh
token.
function browserLocalStorage(): SynqStoragebrowserSessionStorage
Function. The tab's sessionStorage: it ends with the tab, and no other tab reads
it. As the session's store it keeps the access and ID tokens only, never
the refresh token.
function browserSessionStorage(): SynqStorageCHALLENGE_METHODS
Constant. The ways in an app's own screens sign people in with (synq_method).
type CHALLENGE_METHODS // generated from the API's OpenAPI document: see the API referenceCHALLENGE_PROBLEMS
Constant. What went wrong with a step (synq_problem): branch on it, never on the English.
type CHALLENGE_PROBLEMS // generated from the API's OpenAPI document: see the API referenceChallengeMethod
Type. One of CHALLENGE_METHODS.
type ChallengeMethod // generated from the API's OpenAPI document: see the API referenceChallengeProblem
Type. One of CHALLENGE_PROBLEMS.
type ChallengeProblem // generated from the API's OpenAPI document: see the API referenceChangeOptions
Interface. What every change takes.
interface ChangeOptions {
idempotencyKey?: string;
signal?: AbortSignal;
}createAccountClient
Function. A client for the brand's account API, for an app that holds its own session: everything the signed-in person can do to their own account.
function createAccountClient(options: AccountClientOptions): AccountClientcreateSynqClient
Function. A client for one app at one of a brand's Synq issuers.
function createSynqClient(options: SynqClientOptions): SynqClientDeniedReason
Type. One of DENIED_REASONS.
type DeniedReason // generated from the API's OpenAPI document: see the API referenceERROR_CODES
Constant. Each code a Synq API's problem documents carry, with its HTTP status.
type ERROR_CODES // generated from the API's OpenAPI document: see the API referenceIdTokenClaims
Interface. The claims of a validated ID token: who signed in, when, and how.
interface IdTokenClaims {
readonly iss: string;
readonly sub: string;
readonly aud: string | string[];
readonly iat: number;
readonly exp: number;
readonly auth_time?: number;
readonly amr?: string[];
readonly acr?: string;
readonly linked_accounts?: readonly LinkedAccount[];
readonly [claim: string]: unknown;
}isSynqError
Function. Whether error is a SynqError, with code when given.
function isSynqError(error: unknown, code?: SynqAnyErrorCode | undefined): error is SynqErrorLinkedAccount
Interface. One account at an upstream provider the person signs in with, with what
the provider said of it at their last sign-in with it. Someone who links
GitHub and Google to one account is one sub, with two of these.
interface LinkedAccount {
readonly provider: string;
readonly subject: string;
readonly username: string | null;
readonly details_read_at: string | null;
readonly account_type?: string;
readonly created_at?: string;
readonly public_repos?: number;
readonly followers?: number;
readonly email_verified?: boolean;
readonly workspace_domain?: string | null;
readonly test?: true;
}LinkMethod
Type. A way to sign in a link request can add.
type LinkMethod = Schemas['NewLinkRequest']['method'];linkSignIn
Function. The sign-in that finishes a link request, for SynqClient.signIn or
authorizationUrl: a fresh sign-in (prompt=login) carrying the request.
function linkSignIn(request: { readonly authorization_params: { readonly prompt: "login"; readonly synq_intent: "link"; readonly synq_link: string; }; readonly expires_at: string; readonly method: string; }): AuthorizationUrlOptionsManagementComponents
Interface. The management API's schemas, generated from its OpenAPI document.
type ManagementComponents // generated from the API's OpenAPI document: see the API referenceManagementOperations
Type. The management API's operations, generated from its OpenAPI document.
type ManagementOperations // generated from the API's OpenAPI document: see the API referenceManagementPaths
Interface. The management API's paths, generated from its OpenAPI document: what createManagementClient is typed by.
type ManagementPaths // generated from the API's OpenAPI document: see the API referencememoryStorage
Function. Keeps everything in this process's memory: the default, and the only store that holds refresh tokens unless told. Clients that share one share its lock, so they never refresh one session twice at once.
function memoryStorage(): SynqStorageOAuthErrorCode
Type. OAuth's and OpenID Connect's error codes, which Synq's issuers answer with.
type OAuthErrorCode = 'invalid_request' | 'invalid_client' | 'invalid_grant' | 'unauthorized_client' | 'unsupported_grant_type' | 'invalid_scope' | 'invalid_target' | 'access_denied' | 'login_required' | 'consent_required' | 'interaction_required' | 'unmet_authentication_requirements' | 'invalid_token' | 'insufficient_scope' | 'server_error' | 'temporarily_unavailable' | 'invalid_session' | 'redirect_to_web' | 'too_many_requests';PasskeyAssertionJSON
Type. A passkey's assertion, as PublicKeyCredential.toJSON() gives it.
type PasskeyAssertionJSON = Record<string, unknown>;PasskeyRequestOptionsJSON
Type. A passkey's request options, for PublicKeyCredential.parseRequestOptionsFromJSON.
type PasskeyRequestOptionsJSON = Record<string, unknown>;Problem
Type. A problem document from a Synq API (RFC 9457, application/problem+json).
type Problem = {
type?: string;
title?: string;
status?: number;
code?: string;
detail?: string;
[field: string]: unknown;
};problemError
Function. A SynqError for a problem document a Synq API answered with.
function problemError(status: number, problem: Problem, retryAfter?: number | undefined): SynqErrorReadOptions
Interface. What every read takes.
interface ReadOptions {
signal?: AbortSignal;
}RedirectReason
Type. One of REDIRECT_REASONS.
type RedirectReason // generated from the API's OpenAPI document: see the API referenceSavedSignIn
Interface. A flow as toJSON saves it, for resumeSignIn: keep it where only the app reads it.
interface SavedSignIn {
readonly v: 1;
readonly verifier: string;
readonly nonce: string;
readonly scope: string;
readonly resource?: string;
readonly additionalResources?: readonly string[];
readonly acr?: {
readonly values: readonly string[];
readonly essential?: boolean;
};
readonly authSession?: string;
readonly email?: string;
readonly step: SignInFlowStep;
}ServerSignInOptions
Interface. What a server signing people in for its app's own screens adds to a flow (@synqauth/nextjs).
interface ServerSignInOptions {
endUserIp?: string;
}Session
Interface. A signed-in session, without its refresh token, which the client keeps to itself.
interface Session {
readonly accessToken: string;
readonly tokenType: string;
readonly expiresAt: number | undefined;
readonly scope: string | undefined;
readonly idToken: string | undefined;
readonly claims: IdTokenClaims | undefined;
readonly refreshable: boolean;
readonly via: 'hosted' | 'app';
}SessionEvent
Type. A change to the session, as subscribe reports it.
type SessionEvent = {
readonly type: 'signed-in';
readonly session: Session;
} | {
readonly type: 'refreshed';
readonly session: Session;
} | {
readonly type: 'signed-out';
readonly session: null;
};SignInFlow
Class. One sign-in on an app's own screens.
class SignInFlowSignInFlowStep
Type. Where a flow is: what the app's screen asks for now.
type SignInFlowStep = 'start' | 'password' | 'email' | 'code' | 'verify-email' | 'passkey' | 'done';SignInStepResult
Type. What a step of a sign-in came to: what to show next.
type SignInStepResult<S> = {
readonly status: 'signed-in';
readonly session: S;
} | {
readonly status: 'code-sent';
readonly email: string;
readonly expiresAt: Date;
} | {
readonly status: 'verify-email';
readonly email: string;
readonly canSkip: boolean;
} | {
readonly status: 'passkey';
readonly options: PasskeyRequestOptionsJSON;
readonly related?: {
readonly rpId: string;
readonly options: PasskeyRequestOptionsJSON;
};
readonly problem?: ChallengeProblem;
readonly message?: string;
} | {
readonly status: 'retry';
readonly problem: ChallengeProblem;
readonly message: string;
readonly retryAfter?: number;
} | {
readonly status: 'hosted';
readonly reason: RedirectReason;
readonly method?: ChallengeMethod;
readonly loginHint?: string;
continue(): Promise<void>;
} | {
readonly status: 'refused';
readonly reason: DeniedReason;
readonly message: string;
};SignOutOptions
Interface. What signOut takes: where the browser lands afterwards, and the state handed back there.
interface SignOutOptions {
postLogoutRedirectUri?: string;
state?: string;
}StartSignInOptions
Interface. What a sign-in asks for, beyond the client's own.
interface StartSignInOptions {
scope?: string;
resource?: string;
additionalResources?: readonly string[];
acr?: {
readonly values: readonly string[];
readonly essential?: boolean;
};
}SynqAnyErrorCode
Type. Every code a SynqError can carry; an unknown one from a newer Synq passes through as a string.
type SynqAnyErrorCode = SynqErrorCode | OAuthErrorCode | SynqClientErrorCode | (string & Record<never, never>);SynqClient
Interface. A client for one app at one brand's issuer, made by createSynqClient: it
signs people in with the authorization code flow, keeps the session, and
refreshes and ends it.
interface SynqClient {
authorizationUrl(options?: AuthorizationUrlOptions): Promise<URL>;
signIn(options?: AuthorizationUrlOptions): Promise<void>;
handleCallback(url: string | URL): Promise<Session>;
getSession(): Promise<Session | null>;
restoreSession(options?: Omit<AuthorizationUrlOptions, 'prompt'>): Promise<Session | null>;
getAccessToken(options?: {
minValiditySeconds?: number;
}): Promise<string>;
refresh(): Promise<Session>;
subscribe(listener: (event: SessionEvent) => void): () => void;
signOut(options?: SignOutOptions): Promise<URL | null>;
startSignIn(options?: StartSignInOptions & ServerSignInOptions): SignInFlow<Session>;
resumeSignIn(saved: SavedSignIn | string, options?: ServerSignInOptions): SignInFlow<Session>;
}SynqClientErrorCode
Type. The errors the SDK raises itself, before or after asking Synq.
type SynqClientErrorCode = 'invalid_options' | 'discovery_failed' | 'unknown_state' | 'not_signed_in' | 'cancelled' | 'no_refresh_token' | 'invalid_response' | 'network_error' | 'invalid_signature' | 'stale_webhook';SynqClientOptions
Interface. What a Synq client needs to know about the app it signs people in to.
interface SynqClientOptions {
issuer: string | URL;
clientId: string;
clientSecret?: string;
redirectUri: string;
postLogoutRedirectUri?: string;
scope?: string;
resource?: string;
storage?: SynqStorage;
transactionStorage?: SynqStorage;
fetch?: typeof fetch;
refreshLeewaySeconds?: number;
}SynqError
Class. Every error the SDK throws. Branch on code, which is stable: the API's
problem code, OAuth's error, or one of the SDK's own; never on the
message.
class SynqErrorSynqErrorCode
Type. A stable code from a Synq API's problem document: branch on it, never on the English.
type SynqErrorCode // generated from the API's OpenAPI document: see the API referenceSynqStorage
Interface. Where the client keeps what it must remember: the session, and a sign-in's transaction (its PKCE verifier, state and nonce) across the redirect to Synq and back. Any key-value store fits; each method may be async.
Refresh tokens are kept only by a store that says it may hold them
(holdsRefreshTokens): the memory store, or one on a server or in a
device's secure storage. Everything else keeps the session without its
refresh token, which then lives in the client's memory alone, so a refresh
token never lands in localStorage or sessionStorage, where any script
on the page reads it.
Synq rotates refresh tokens and ends the whole grant when a used one comes
back, so only one refresh may run at a time for one session. One client
makes sure of that by itself. When several clients share a store (requests
on one server, or replicas sharing a cookie or Redis), the store must give
them a lock (lock); a store without one is for one client per process.
interface SynqStorage {
get(key: string): string | null | undefined | Promise<string | null | undefined>;
set(key: string, value: string): void | Promise<void>;
remove(key: string): void | Promise<void>;
readonly holdsRefreshTokens?: boolean;
lock?<T>(name: string, fn: () => Promise<T>): Promise<T>;
keys?(): Iterable<string> | Promise<Iterable<string>>;
}TestAccount
Interface. A made-up GitHub or Google account for a test sign-in, on
Synq's stages other than production, for an app with test_sign_ins on:
who the person is there, and what the provider says of the account.
Unnamed details take an ordinary account's (a year old, one public
repository; a verified personal Google account). It becomes a linked
account with test: true, a subject of test-<account>, and an address
Synq never verifies.
interface TestAccount {
readonly provider: 'github' | 'google';
readonly account: string;
readonly username?: string;
readonly email?: string;
readonly name?: string;
readonly accountType?: 'User' | 'Organization' | 'Bot';
readonly accountAgeDays?: number;
readonly createdAt?: string;
readonly publicRepos?: number;
readonly followers?: number;
readonly emailVerified?: boolean;
readonly workspaceDomain?: string;
}@synqauth/js/server
AccessTokenClaims
Interface. A Synq access token's claims (RFC 9068), once checked.
interface AccessTokenClaims {
readonly iss: string;
readonly sub: string;
readonly aud: string | string[];
readonly azp: string | undefined;
readonly scopes: readonly string[];
readonly iat: number;
readonly exp: number;
readonly auth_time: number | undefined;
readonly acr: string | undefined;
readonly amr: readonly string[] | undefined;
readonly act: {
readonly type?: string;
readonly client_id?: string;
} | undefined;
readonly email: string | undefined;
readonly email_verified: boolean | undefined;
readonly linked_accounts: readonly LinkedAccount[] | undefined;
readonly payload: JWTPayload;
}AccessTokenVerifier
Type. Checks one access token for your API, as createAccessTokenVerifier makes
it: the claims when the token is good, else a SynqError
(invalid_token, insufficient_scope or fresh_sign_in_required).
type AccessTokenVerifier = (token: string, options?: VerifyAccessTokenOptions) => Promise<AccessTokenClaims>;AccessTokenVerifierOptions
Interface. What an API checks every access token against.
interface AccessTokenVerifierOptions {
issuer: string;
audience: string;
algorithms?: string[];
clockToleranceSeconds?: number;
fetch?: typeof fetch;
keys?: JWTVerifyGetKey;
}ApiKeyClaims
Interface. One of your users' API keys, once Synq said it works.
interface ApiKeyClaims {
readonly iss: string;
readonly sub: string;
readonly aud: string;
readonly scopes: readonly string[];
readonly keyId: string;
readonly name: string;
readonly iat: number;
readonly exp: number | undefined;
readonly email: string | undefined;
readonly email_verified: boolean | undefined;
readonly linked_accounts: readonly LinkedAccount[] | undefined;
}ApiKeyVerifier
Type. Checks one of your users' API keys, as createApiKeyVerifier makes it:
the claims when the key works, else a SynqError (invalid_token for a
key that doesn't, insufficient_scope for one without a scope asked for).
type ApiKeyVerifier = (key: string, options?: VerifyApiKeyOptions) => Promise<ApiKeyClaims>;ApiKeyVerifierOptions
Interface. What an API checks its users' API keys with: the brand's issuer, and the API's own app.
interface ApiKeyVerifierOptions {
issuer: string;
clientId: string;
clientSecret: string;
fetch?: typeof fetch;
}createAccessTokenVerifier
Function. A verifier for one API's access tokens. It reads the issuer's JWKS once and keeps it, fetching it again when a token names a key it doesn't have (a rotation), at most every 30 seconds. A discovery that failed is retried after 30 seconds, not on every token. Keep one per API, not one per request. The issuer and its JWKS must be https (http only on this machine).
function createAccessTokenVerifier(options: AccessTokenVerifierOptions): AccessTokenVerifiercreateApiKeyVerifier
Function. A verifier for the API keys your users make for your API. It
asks the brand's issuer about every key (POST /api-keys/verify, as the
API's own app), and keeps nothing: revoking a key works from its next
check. A key Synq says doesn't work is invalid_token (401), never why;
your app's credentials refused are invalid_client.
function createApiKeyVerifier(options: ApiKeyVerifierOptions): ApiKeyVerifiercreateManagementClient
Function. A client for Synq's management API (/v1), typed by its contract. Server
only: an API key never reaches a browser. Failures throw a SynqError
with the problem's code, such as insufficient_permissions.
function createManagementClient(options: ManagementClientOptions): ManagementClientcreateOwnUiSignIn
Function. Own-UI sign-in for a server: its forms post to it, it calls
Synq's Authorization Challenge Endpoint as its app, and a sign-in ends
with tokens, not a cookie at Synq. The app keeps them, and the person's
password or code never reaches a browser but the form they typed it in.
hosted results can't continue() here: send the browser to an
ordinary authorization request with the method and loginHint given.
function createOwnUiSignIn(options: OwnUiSignInOptions): OwnUiSignInisApiKey
Function. Whether credential is one of your users' API keys (ak_live_… or
ak_test_…,) rather than an access token: what tells an API
which of createApiKeyVerifier and createAccessTokenVerifier to check
a bearer credential with.
function isApiKey(credential: unknown): credential is stringisSynqError
Function. Whether error is a SynqError, with code when given.
function isSynqError(error: unknown, code?: SynqAnyErrorCode | undefined): error is SynqErrorLinkedAccount
Interface. One account at an upstream provider the person signs in with, with what
the provider said of it at their last sign-in with it. Someone who links
GitHub and Google to one account is one sub, with two of these.
interface LinkedAccount {
readonly provider: string;
readonly subject: string;
readonly username: string | null;
readonly details_read_at: string | null;
readonly account_type?: string;
readonly created_at?: string;
readonly public_repos?: number;
readonly followers?: number;
readonly email_verified?: boolean;
readonly workspace_domain?: string | null;
readonly test?: true;
}ManagementClient
Type. The management API's typed client: every path, parameter, body and answer from its contract.
type ManagementClient = ApiClient<paths>;ManagementClientOptions
Interface. Who a management API client acts as.
interface ManagementClientOptions {
baseUrl: string;
apiKey?: string;
accessToken?: () => string | Promise<string>;
fetch?: typeof fetch;
}ManagementComponents
Interface. The management API's schemas, generated from its OpenAPI document.
type ManagementComponents // generated from the API's OpenAPI document: see the API referenceManagementPaths
Interface. The management API's paths, generated from its OpenAPI document: what createManagementClient is typed by.
type ManagementPaths // generated from the API's OpenAPI document: see the API referenceOwnUiSignIn
Interface. A server's own-UI sign-ins: one flow per sign-in, kept between requests with toJSON.
interface OwnUiSignIn {
start(options?: StartSignInOptions & {
endUserIp?: string;
}): SignInFlow<OwnUiTokens>;
resume(saved: SavedSignIn | string, options?: {
endUserIp?: string;
}): SignInFlow<OwnUiTokens>;
}OwnUiSignInOptions
Interface. What a server needs to sign people in on its app's own screens.
interface OwnUiSignInOptions {
issuer: string;
clientId: string;
clientSecret?: string;
privateKey?: CryptoKey | {
key: CryptoKey;
kid?: string;
};
fetch?: typeof fetch;
}OwnUiTokens
Interface. What a server's own-UI sign-in ends with: the app keeps them as its session.
interface OwnUiTokens {
readonly accessToken: string;
readonly tokenType: string;
readonly expiresAt: number | undefined;
readonly scope: string | undefined;
readonly idToken: string;
readonly refreshToken: string | undefined;
readonly claims: IdTokenClaims;
}SavedSignIn
Interface. A flow as toJSON saves it, for resumeSignIn: keep it where only the app reads it.
interface SavedSignIn {
readonly v: 1;
readonly verifier: string;
readonly nonce: string;
readonly scope: string;
readonly resource?: string;
readonly additionalResources?: readonly string[];
readonly acr?: {
readonly values: readonly string[];
readonly essential?: boolean;
};
readonly authSession?: string;
readonly email?: string;
readonly step: SignInFlowStep;
}SignInFlow
Class. One sign-in on an app's own screens.
class SignInFlowSignInFlowStep
Type. Where a flow is: what the app's screen asks for now.
type SignInFlowStep = 'start' | 'password' | 'email' | 'code' | 'verify-email' | 'passkey' | 'done';SignInStepResult
Type. What a step of a sign-in came to: what to show next.
type SignInStepResult<S> = {
readonly status: 'signed-in';
readonly session: S;
} | {
readonly status: 'code-sent';
readonly email: string;
readonly expiresAt: Date;
} | {
readonly status: 'verify-email';
readonly email: string;
readonly canSkip: boolean;
} | {
readonly status: 'passkey';
readonly options: PasskeyRequestOptionsJSON;
readonly related?: {
readonly rpId: string;
readonly options: PasskeyRequestOptionsJSON;
};
readonly problem?: ChallengeProblem;
readonly message?: string;
} | {
readonly status: 'retry';
readonly problem: ChallengeProblem;
readonly message: string;
readonly retryAfter?: number;
} | {
readonly status: 'hosted';
readonly reason: RedirectReason;
readonly method?: ChallengeMethod;
readonly loginHint?: string;
continue(): Promise<void>;
} | {
readonly status: 'refused';
readonly reason: DeniedReason;
readonly message: string;
};StartSignInOptions
Interface. What a sign-in asks for, beyond the client's own.
interface StartSignInOptions {
scope?: string;
resource?: string;
additionalResources?: readonly string[];
acr?: {
readonly values: readonly string[];
readonly essential?: boolean;
};
}SynqError
Class. Every error the SDK throws. Branch on code, which is stable: the API's
problem code, OAuth's error, or one of the SDK's own; never on the
message.
class SynqErrorVerifiedWebhook
Interface. A delivery that passed its check.
interface VerifiedWebhook {
readonly id: string;
readonly timestamp: Date;
readonly event: WebhookEvent;
}VerifyAccessTokenOptions
Interface. What one route wants of a token, on top of the verifier's checks.
interface VerifyAccessTokenOptions {
scopes?: readonly string[];
authorizedParties?: readonly string[];
maxAuthAgeSeconds?: number;
}VerifyApiKeyOptions
Interface. What one route wants of a key, on top of the verifier's checks.
interface VerifyApiKeyOptions {
scopes?: readonly string[];
}verifyWebhook
Function. Checks a delivery's Standard Webhooks signature (webhook-id,
webhook-timestamp, webhook-signature, HMAC-SHA256 over
<id>.<timestamp>.<body>) against the subscription's whsec_ secret, and
that Synq signed it within toleranceSeconds (5 minutes by default), so a
captured delivery can't be replayed later. Pass both secrets while one is
being rotated: Synq signs with both for 24 hours. body is the request's
raw body, exactly as it arrived.
function verifyWebhook(body: string, headers: HeadersLike, secrets: string | readonly string[], options?: { toleranceSeconds?: number | undefined; now?: Date | undefined; }): Promise<VerifiedWebhook>WebhookEvent
Type. A Synq webhook's event: one row of the org's audit log (the management API's WebhookEvent).
type WebhookEvent = components['schemas']['WebhookEvent'];See every package.