@synqauth/react
React hooks and components for Synq.
@synqauth/react
AccountManager
Component. Manage the signed-in person's account. Nothing while nobody is signed in.
function AccountManager({ unstyled, className, sections, }: AccountManagerProps): ReactNodeAccountManagerProps
Interface. What AccountManager takes: which sections it shows, and its look.
interface AccountManagerProps extends SynqStyleProps {
readonly sections?: readonly AccountSection[];
}AccountSection
Type. One part of AccountManager: the profile, the ways to sign in, the sessions, or the API keys.
type AccountSection = 'profile' | 'accounts' | 'sessions' | 'apiKeys';AccountSession
Type. One of the person's sessions at the brand, on some device.
type AccountSession = AccountComponents['schemas']['Session'];ApiKey
Type. One of the person's API keys for the brand's APIs: never the key itself.
type ApiKey = AccountComponents['schemas']['UserApiKey'];ApiKeyInput
Type. What making an API key takes: the API's identifier, a name, its scopes, an expiry if any.
type ApiKeyInput = AccountComponents['schemas']['UserApiKeyCreate'];DEFAULT_MESSAGES
Constant. The components' English words, which an app's own messages override one by one.
const DEFAULT_MESSAGES: SynqMessagesEmailCodeForm
Component. An emailed code: the address to send it to, then the code it held.
function EmailCodeForm({ signIn, autofill, unstyled, className, }: SignInPartProps & { readonly autofill?: boolean | undefined; }): ReactNodeKeyableApi
Type. One of the brand's APIs the person may make keys for, with the scopes it defines.
type KeyableApi = AccountComponents['schemas']['KeyableApi'];LinkedAccount
Type. A way the person signs in: their email address, a wallet, a Google account...
type LinkedAccount = AccountComponents['schemas']['Identity'];NewApiKey
Type. A key just made: key is the key itself, in this answer only.
type NewApiKey = AccountComponents['schemas']['NewUserApiKey'];OneTimeCodeInput
Component. The field for an emailed code, named code: digits, filled from the message where the device can.
function OneTimeCodeInput({ label, unstyled, className, ...input }: OneTimeCodeInputProps): ReactNodeOneTimeCodeInputProps
Interface. What OneTimeCodeInput takes: its label, its look, and any input attribute.
interface OneTimeCodeInputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className'>, SynqStyleProps {
readonly label: ReactNode;
}PasskeyButton
Component. The button for a passkey: the brand's, or with related its own host's on its custom domain.
function PasskeyButton({ signIn, related, children, unstyled, className, }: SignInPartProps & { readonly related?: boolean | undefined; readonly children?: ReactNode; }): ReactNodePasswordForm
Component. An email address and a password: signs in, or with screen="sign-up"
makes an account. With emailCode, it offers a code by email for the
same address too.
function PasswordForm({ signIn, screen, emailCode, autofill, unstyled, className, }: SignInPartProps & { readonly screen?: "sign-in" | "sign-up" | undefined; readonly emailCode?: boolean | undefined; readonly autofill?: boolean | undefined; }): ReactNodeProfile
Type. The person's profile at the brand.
type Profile = AccountComponents['schemas']['Profile'];ProfileUpdate
Type. Changes to it: only the fields given change, and null clears one.
type ProfileUpdate = AccountComponents['schemas']['ProfileUpdate'];SessionStatus
Type. error when the app couldn't be asked who is signed in, and nothing is known yet: the provider asks again, waiting longer each time.
type SessionStatus = 'loading' | 'signed-in' | 'signed-out' | 'error';SignedIn
Component. Shows its children only while someone is signed in. It renders no element of its own.
function SignedIn({ children }: { readonly children?: ReactNode; }): ReactNodeSignedOut
Component. Shows its children only once the app has said nobody is signed in. It renders no element of its own.
function SignedOut({ children }: { readonly children?: ReactNode; }): ReactNodeSignInButton
Component. A button that sends the browser to sign in, through the app's route mount.
function SignInButton({ unstyled, className, children, ...options }: SignInButtonProps): ReactNodeSignInButtonProps
Interface. What SignInButton takes: the sign-in's options, its look and its words.
interface SignInButtonProps extends SignInOptions, SynqStyleProps {
readonly children?: ReactNode;
}SignInForm
Component. Sign-in on the app's own page: a passkey where the browser takes the issuer's, then an emailed code or a password, and the code or the new address's proof after. Whatever only the hosted page can do, it goes there for.
function SignInForm({ methods, screen: initialScreen, returnTo, onSignedIn, unstyled, className, }: SignInFormProps): ReactNodeSignInFormProps
Interface. What SignInForm takes: which ways to offer, where it starts, and its look.
interface SignInFormProps extends UseSignInOptions, SynqStyleProps {
readonly methods?: readonly ChallengeMethod[];
readonly screen?: 'sign-in' | 'sign-up';
}SignInHandover
Interface. What only the hosted page can do for this sign-in, and what to take there.
interface SignInHandover {
readonly reason: RedirectReason;
readonly method?: ChallengeMethod;
readonly loginHint?: string;
}SignInMethod
Type. One of the brand's sign-in methods.
type SignInMethod = Extract<keyof SignInMethods, string>;SignInMethods
Interface. The ways a brand signs people in, as synq_method names them: the hosted
page goes straight to one. A brand's own connection joins them the same way:
``ts declare module '@synqauth/react' { interface SignInMethods { okta: true } } ``
interface SignInMethods {
readonly password: true;
readonly email: true;
readonly passkey: true;
readonly wallet: true;
readonly google: true;
readonly github: true;
readonly microsoft: true;
readonly discord: true;
}SignInOptions
Interface. How to send the person to sign in.
interface SignInOptions {
readonly returnTo?: string;
readonly method?: SignInMethod;
readonly loginHint?: string;
readonly prompt?: 'login' | 'none' | 'consent' | 'select_account' | 'create';
readonly maxAge?: number;
readonly intent?: 'add-passkey';
}SignInPartProps
Interface. What each part of the form takes: the sign-in it works on, and its look.
interface SignInPartProps extends SynqStyleProps {
readonly signIn: UseSignIn;
}SignInProblem
Interface. What went wrong with the last step: branch on code, never on the English.
interface SignInProblem {
readonly code: ChallengeProblem | 'expired' | 'refused' | 'passkey_cancelled' | 'unavailable';
readonly reason?: DeniedReason;
readonly message: string;
readonly retryAfter?: number;
}SignInStep
Type. Where a sign-in is: what the form shows.
type SignInStep = 'start' | 'code' | 'verify-email' | 'done';SynqClientPlugin
Interface. A browser plugin: actions over its server plugin's routes. The same shape
as @synqauth/nextjs/client's defineSynqClientPlugin, so its plugins
work here as they are.
interface SynqClientPlugin<Id extends string = string, Actions = unknown> {
readonly id: Id;
actions(request: SynqMountRequest): Actions;
}SynqMessages
Interface. Every word the components show, for <SynqProvider messages>; any left out stay English.
interface SynqMessages {
readonly signIn: string;
readonly signOut: string;
readonly manageAccount: string;
readonly account: string;
readonly loading: string;
readonly save: string;
readonly saving: string;
readonly saved: string;
readonly cancel: string;
readonly profile: string;
readonly name: string;
readonly username: string;
readonly waysToSignIn: string;
readonly remove: string;
readonly removeAccount: (provider: string, subject: string) => string;
readonly providers: Readonly<Record<string, string>>;
readonly devices: string;
readonly signedIn: string;
readonly thisDevice: string;
readonly signOutDevice: (when: string) => string;
readonly apps: (count: number) => string;
readonly wallets: string;
readonly noWallets: string;
readonly primary: string;
readonly rename: string;
readonly renameWallet: (name: string) => string;
readonly makePrimary: string;
readonly makeWalletPrimary: (name: string) => string;
readonly walletName: (address: string) => string;
readonly apiKeys: string;
readonly noApiKeys: string;
readonly newApiKey: string;
readonly api: string;
readonly keyScopes: string;
readonly expires: string;
readonly never: string;
readonly inDays: (days: number) => string;
readonly makeKey: string;
readonly makingKey: string;
readonly revoke: string;
readonly revokeKey: (name: string) => string;
readonly revoked: string;
readonly expired: string;
readonly lastUsed: (when: string) => string;
readonly neverUsed: string;
readonly expiresOn: (when: string) => string;
readonly copyKeyNow: string;
readonly copy: string;
readonly copied: string;
readonly done: string;
readonly keyNeedsFreshSignIn: string;
readonly signInAgain: string;
readonly email: string;
readonly password: string;
readonly signInWithPasskey: string;
readonly passkeyFor: (domain: string) => string;
readonly emailMeACode: string;
readonly or: string;
readonly code: string;
readonly codeSentTo: (email: string) => string;
readonly verifyYourEmail: (email: string) => string;
readonly verify: string;
readonly sendAnotherCode: string;
readonly useAnotherWay: string;
readonly skipForNow: string;
readonly forgotPassword: string;
readonly createAccount: string;
readonly newHere: string;
readonly haveAnAccount: string;
readonly continuingToSignIn: string;
readonly tryAgainIn: (seconds: number) => string;
readonly signInProblems: Readonly<Partial<Record<SignInProblem['code'], string>>>;
readonly signInRefusals: Readonly<Partial<Record<DeniedReason, string>>>;
}SynqMountRequest
Type. Calls the app's route mount: request('session'), request('account/v1/profile', { method: 'PATCH',... }).
type SynqMountRequest = (path: string, init?: RequestInit) => Promise<Response>;SynqProvider
Component. Synq for the components under it. Its route mount and fetch are read once, when it mounts.
function SynqProvider({ initialSession, basePath, plugins, fetch: fetcher, navigate, messages, children, }: SynqProviderProps): ReactNodeSynqProviderProps
Interface. What SynqProvider takes: the server's session, the route mount, the words and the plugins.
interface SynqProviderProps {
readonly initialSession?: SynqSessionInfo | null;
readonly basePath?: string;
readonly plugins?: readonly SynqClientPlugin[];
readonly fetch?: typeof fetch;
readonly navigate?: (url: string) => void;
readonly messages?: Partial<SynqMessages>;
readonly children?: ReactNode;
}SynqResult
Type. A call's outcome: its data, or the SynqError it failed with (branch on error.code).
type SynqResult<T> = {
readonly data: T;
readonly error: null;
} | {
readonly data: null;
readonly error: SynqError;
};SynqSessionInfo
Interface. Who is signed in, as the app's server tells the browser: await synq.getSession(), or the route mount's session.
interface SynqSessionInfo {
readonly user: SynqUser | null;
readonly expiresAt: number | null;
}SynqStyleProps
Interface. What every component takes for its look: Synq's classes, or unstyled.
interface SynqStyleProps {
readonly unstyled?: boolean;
readonly className?: string;
}SynqUser
Interface. A signed-in person, from the ID token Synq issued at sign-in.
interface SynqUser {
readonly sub: string;
readonly email?: string;
readonly email_verified?: boolean;
readonly name?: string;
readonly preferred_username?: string;
readonly picture?: string;
readonly auth_time?: number;
readonly amr?: readonly string[];
readonly [claim: string]: unknown;
}UseAccountData
Interface. What the account hooks (useWallets, useLinkedAccounts, useAccountSessions) answer: the data, the error, and whether it loaded.
interface UseAccountData<T> {
readonly data: T | null;
readonly error: SynqError | null;
readonly isLoading: boolean;
readonly reload: () => Promise<void>;
}useAccountSessions
Function. The person's sessions at the brand, on every device.
function useAccountSessions(): UseAccountData<readonly { readonly amr: readonly string[]; readonly apps: readonly string[]; readonly current: boolean; readonly expires_at: string | null; readonly id: string; readonly signed_in_at: string | null; readonly via: "hosted" | "app"; }[]>useApiKeys
Function. The person's API keys for the brand's APIs, revoked and expired ones too.
function useApiKeys(): UseAccountData<readonly { readonly api: { readonly identifier: string; readonly name: string; }; readonly created_at: string; readonly expires_at: string | null; readonly id: string; readonly last_used_at: string | null; readonly name: string; readonly prefix: string; readonly revoked_at: string | null; readonly scopes: readonly string[]; }[]>useAuth
Function. Everything the signed-in person can do.
function useAuth(): UseAuthUseAuth
Interface. What useAuth() answers: signIn, signOut, link, and the account's wallets, ways to sign in and sessions.
interface UseAuth {
readonly isLoaded: boolean;
readonly isSignedIn: boolean;
readonly userId: string | null;
readonly signIn: (options?: SignInOptions) => void;
readonly signInUrl: (options?: SignInOptions) => string;
readonly signOut: () => Promise<SynqResult<null>>;
readonly link: (method: SignInMethod, options?: {
returnTo?: string;
}) => Promise<SynqResult<null>>;
readonly wallets: {
readonly list: () => Promise<SynqResult<readonly Wallet[]>>;
readonly rename: (id: string, label: string | null) => Promise<SynqResult<Wallet>>;
readonly setPrimary: (id: string) => Promise<SynqResult<Wallet>>;
};
readonly accounts: {
readonly list: () => Promise<SynqResult<readonly LinkedAccount[]>>;
readonly unlink: (id: string) => Promise<SynqResult<null>>;
};
readonly sessions: {
readonly list: () => Promise<SynqResult<readonly AccountSession[]>>;
readonly end: (id: string) => Promise<SynqResult<null>>;
};
readonly apiKeys: {
readonly list: () => Promise<SynqResult<readonly ApiKey[]>>;
readonly create: (input: ApiKeyInput) => Promise<SynqResult<NewApiKey>>;
readonly revoke: (id: string) => Promise<SynqResult<null>>;
};
readonly plugins: Readonly<Record<string, unknown>>;
}useKeyableApis
Function. The brand's APIs that let the person make keys, with the scopes each defines.
function useKeyableApis(): UseAccountData<readonly { readonly identifier: string; readonly name: string; readonly scopes: readonly { readonly description: string; readonly name: string; }[]; }[]>useLinkedAccounts
Function. The ways the person signs in: their email address, wallets, social accounts.
function useLinkedAccounts(): UseAccountData<readonly { readonly created_at: string; readonly handle: string | null; readonly id: string; readonly last_used_at: string | null; readonly password?: boolean | undefined; readonly provider: string; readonly subject: string; }[]>usePlugin
Function. A browser plugin's actions, typed by the plugin, which must be one of the provider's plugins.
function usePlugin<Actions>(plugin: SynqClientPlugin<string, Actions>): ActionsUserButton
Component. The signed-in person's picture and name, showing a panel to manage their account or sign out: a disclosure (a button that shows and hides it), so its link and button are reached with Tab as anywhere else. Escape or a click elsewhere hides it. Nothing while nobody is signed in.
function UserButton({ unstyled, className, accountHref }: UserButtonProps): ReactNodeUserButtonProps
Interface. What UserButton takes: where its account link goes, and its look.
interface UserButtonProps extends SynqStyleProps {
readonly accountHref?: string;
}UserMetadata
Interface. What the brand keeps for the person (the account API's metadata).
Augment it to type what the app reads:
``ts declare module '@synqauth/react' { interface UserMetadata { plan?: 'free' | 'pro' } } ``
interface UserMetadata {
readonly [field: string]: unknown;
}useSession
Function. Who is signed in. It reads the session alone, and asks the account API nothing.
function useSession(): UseSessionUseSession
Interface. What useSession() answers: who is signed in, and whether the app said yet.
interface UseSession {
readonly status: SessionStatus;
readonly isLoaded: boolean;
readonly isSignedIn: boolean;
readonly user: SynqUser | null;
readonly expiresAt: number | null;
readonly error: SynqError | null;
readonly refresh: () => Promise<void>;
}useSignIn
Function. One sign-in on the app's own screens, through the route mount's sign-in/flow.
function useSignIn(options?: UseSignInOptions): UseSignInUseSignIn
Interface. What useSignIn() answers: the sign-in's step, what went wrong, and each method's steps.
interface UseSignIn {
readonly step: SignInStep;
readonly pending: boolean;
readonly problem: SignInProblem | null;
readonly email: string | undefined;
readonly canSkip: boolean;
readonly handover: SignInHandover | null;
readonly password: {
readonly signIn: (input: {
email: string;
password: string;
}) => Promise<void>;
readonly signUp: (input: {
email: string;
password: string;
}) => Promise<void>;
};
readonly emailCode: {
readonly send: (email: string) => Promise<void>;
readonly verify: (code: string) => Promise<void>;
readonly resend: () => Promise<void>;
};
readonly passkey: {
readonly supported: boolean;
readonly autofill: boolean;
readonly relatedDomain: string | null;
readonly signIn: (options?: {
related?: boolean;
}) => Promise<void>;
readonly startAutofill: () => Promise<void>;
};
readonly verifyEmail: {
readonly verify: (code: string) => Promise<void>;
readonly resend: () => Promise<void>;
readonly skip: () => Promise<void>;
};
readonly continueOnHostedPage: (options?: {
method?: ChallengeMethod;
loginHint?: string;
}) => void;
readonly startOver: () => Promise<void>;
}UseSignInOptions
Interface. What useSignIn() takes: where to go once signed in, or what to do instead.
interface UseSignInOptions {
readonly returnTo?: string;
readonly onSignedIn?: (returnTo: string) => void;
}useUser
Function. The signed-in person: their ID token's claims at once, then their profile and metadata.
function useUser(): UseUserUseUser
Interface. What useUser() answers: the person's claims, profile and metadata, and update for the profile.
interface UseUser {
readonly isLoaded: boolean;
readonly isSignedIn: boolean;
readonly user: SynqUser | null;
readonly profile: Profile | null;
readonly metadata: UserMetadata | null;
readonly isLoading: boolean;
readonly error: SynqError | null;
readonly update: (changes: ProfileUpdate) => Promise<SynqResult<Profile>>;
readonly reload: () => Promise<void>;
}useWallets
Function. The person's wallets, the primary one marked.
function useWallets(): UseAccountData<readonly { readonly address: string; readonly created_at: string; readonly id: string; readonly label: string | null; readonly last_used_at: string | null; readonly primary: boolean; }[]>VerifyEmailForm
Component. The code that proves a new account's address, or "Skip for now" where the brand allows.
function VerifyEmailForm({ signIn, unstyled, className }: SignInPartProps): ReactNodeWallet
Type. A Solana wallet the person signs in with.
type Wallet = AccountComponents['schemas']['Wallet'];WalletManager
Component. Manage the signed-in person's wallets. Nothing while nobody is signed in.
function WalletManager({ unstyled, className }: SynqStyleProps): ReactNodeWalletManagerProps
Type. What WalletManager takes: its look.
type WalletManagerProps = SynqStyleProps;See every package.