@synqauth/nextjs
Synq for Next.js: a backend-for-frontend session, so the browser never holds a Synq token.
@synqauth/nextjs
createSynqCore
Function. The framework-neutral core synqAuth() runs on, over any cookie jar: for
a server that answers the same routes without Next. Most apps use
synqAuth() instead.
function createSynqCore(config: SynqConfig): SynqCoredefineSynqConfig
Function. Declares the app's Synq configuration: SYNQ_* environment variables fill in whatever it leaves out.
function defineSynqConfig<const T extends SynqAuthOptions>(options: T): TdefineSynqPlugin
Function. Declares a server plugin, checking its id and routes once, when the module loads.
function defineSynqPlugin<const T extends SynqPlugin>(plugin: T): TjarOf
Function. Next's cookie store as the cookie jar createSynqCore reads and writes.
function jarOf(store: Omit<RequestCookies, "set" | "clear" | "delete"> & Pick<ResponseCookies, "set" | "delete">): CookieJarKeyValue
Interface. The few operations a key-value store (Redis, Valkey, Upstash...) gives keyValueSessionStore.
interface KeyValue {
get(key: string): Promise<string | null | undefined>;
set(key: string, value: string, options: {
ttlMs: number;
onlyIfAbsent?: boolean;
}): Promise<boolean>;
delete(key: string): Promise<void>;
deleteIfEquals?(key: string, value: string): Promise<void>;
}keyValueSessionStore
Function. Sessions in a key-value store every server process shares, such as Redis
or Valkey: the store an app on several processes (replicas, serverless
functions) needs. Its lock is SET … NX PX with a token, polled until
free, and released only by its holder; it expires on its own, so a dead
process never holds a session for ever.
``ts keyValueSessionStore({ get: (key) => redis.get(key), set: async (key, value, { ttlMs, onlyIfAbsent }) => (await redis.set(key, value, { PX: ttlMs, NX: onlyIfAbsent })) === 'OK', delete: async (key) => void (await redis.del(key)), }) ``
function keyValueSessionStore(kv: KeyValue, options?: KeyValueSessionStoreOptions): SynqSessionStoreKeyValueSessionStoreOptions
Interface. What keyValueSessionStore takes besides the store itself.
interface KeyValueSessionStoreOptions {
prefix?: string;
lockTtlMs?: number;
lockWaitMs?: number;
}memorySessionStore
Function. A store in this process's memory: for tests and a single server process, where the default cookie does as well.
function memorySessionStore(): SynqSessionStoreresolveConfig
Function. The configuration from options and the environment; throws invalid_options for anything missing or unsafe.
function resolveConfig(options?: SynqAuthOptions, env?: Env): SynqConfigSessionValues
Type. What a session keeps: tokens per API and the refresh token, as strings.
type SessionValues = Record<string, string>;SIGN_IN_ERROR_PARAM
Constant. The query parameter the route mount adds to returnTo when a sign-in fails.
const SIGN_IN_ERROR_PARAM: "synq_error"signInErrorMessage
Function. What a sign-in error code means, in plain words.
function signInErrorMessage(code: string): stringsynqAuth
Function. Synq for this app, configured from SYNQ_ISSUER, SYNQ_CLIENT_ID,
SYNQ_CLIENT_SECRET, SYNQ_APP_URL and SYNQ_SESSION_SECRET unless options
(defineSynqConfig, shared with the proxy) says.
function synqAuth(options?: SynqAuthOptions): SynqAuthSynqAuth
Interface. What synqAuth() returns: the route mount's handlers and the server's view of the session.
interface SynqAuth {
readonly handlers: {
readonly GET: (request: Request) => Promise<Response>;
readonly POST: (request: Request) => Promise<Response>;
readonly PATCH: (request: Request) => Promise<Response>;
readonly DELETE: (request: Request) => Promise<Response>;
};
me(): Promise<SynqUser | null>;
getSession(): Promise<SynqSessionInfo>;
getAccessToken(options?: {
resource?: string;
minValiditySeconds?: number;
}): Promise<string>;
signInPath(options?: {
returnTo?: string;
method?: string;
loginHint?: string;
prompt?: 'login' | 'none' | 'consent' | 'select_account' | 'create';
maxAge?: number;
}): string;
readonly signOutPath: string;
signInError(searchParams: URLSearchParams | Record<string, string | string[] | undefined>, returnTo?: string): SynqSignInError | null;
}SynqAuthOptions
Interface. What synqAuth() and defineSynqConfig() take. Every option the
environment can give (SYNQ_*) is optional here; an option given wins.
interface SynqAuthOptions {
issuer?: string;
clientId?: string;
clientSecret?: string;
appUrl?: string;
sessionSecret?: string;
previousSessionSecrets?: readonly string[];
basePath?: string;
resource?: string;
account?: boolean;
scope?: string;
postLogoutRedirectUri?: string;
store?: SynqSessionStore;
allowSingleProcessCookieMode?: boolean;
sessionMaxAge?: number;
refreshLeewaySeconds?: number;
plugins?: readonly SynqPlugin[];
fetch?: typeof fetch;
clientAddress?: (request: Request) => string | undefined;
}SynqPlugin
Interface. A server plugin: routes under the route mount, at <basePath>/<id>/…. Declare one with defineSynqPlugin.
interface SynqPlugin {
readonly id: string;
readonly routes?: Readonly<Record<string, SynqPluginRoute>>;
}SynqPluginContext
Interface. What a plugin's route is handed.
interface SynqPluginContext {
user(): Promise<SynqUser | null>;
getAccessToken(options?: {
resource?: string;
}): Promise<string>;
readonly issuer: string;
readonly clientId: string;
readonly basePath: string;
}SynqPluginRoute
Type. A route: GET /status, POST /verify... relative to the plugin's own path.
type SynqPluginRoute = (context: SynqPluginContext, request: Request) => Response | Promise<Response>;SynqSessionInfo
Interface. Who is signed in, as the browser may see it: never a token.
interface SynqSessionInfo {
readonly user: SynqUser | null;
readonly expiresAt: number | null;
}SynqSessionStore
Interface. Where sessions live server-side when the cookie holds only the session's
id (synqAuth({ store })): needed where several processes serve the app.
keyValueSessionStore makes one from any key-value store.
interface SynqSessionStore {
get(id: string): Promise<SessionValues | null>;
set(id: string, values: SessionValues, maxAgeSeconds: number): Promise<void>;
delete(id: string): Promise<void>;
lock<T>(id: string, fn: () => Promise<T>): Promise<T>;
}SynqSignInError
Interface. Why the last sign-in didn't finish, and the ways on.
interface SynqSignInError {
readonly code: string;
readonly message: string;
readonly retryPath: string;
readonly anotherAccountPath: 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 linked_accounts?: readonly LinkedAccount[];
readonly [claim: string]: unknown;
}@synqauth/nextjs/proxy
SignUpChoice
Interface. What a visitor picked: a plan's code and its interval, and the onboarding visit.
interface SignUpChoice {
readonly plan?: string;
readonly interval?: 'month' | 'year';
readonly onboarding?: string;
}synqProxy
Function. Next's proxy for Synq: refreshes a session that is due, and sends a request to a protected path without one to sign in, or, when a sign-in just failed, to the page that says why.
function synqProxy(config: SynqAuthOptions, options: SynqProxyOptions): (request: Request) => Promise<Response | undefined>SynqProxyOptions
Interface. What synqProxy() takes: which paths need a session.
interface SynqProxyOptions {
readonly protect: readonly string[] | ((pathname: string) => boolean);
readonly signInError?: string;
readonly signUp?: readonly string[] | ((pathname: string) => boolean);
readonly choice?: (url: URL) => SignUpChoice | undefined;
}@synqauth/nextjs/client
defineSynqClientPlugin
Function. Declares a browser plugin, its id the same as its server plugin's.
function defineSynqClientPlugin<const Id extends string, Actions>(plugin: SynqClientPlugin<Id, Actions>): SynqClientPlugin<Id, Actions>mountRequest
Function. A request to basePath's routes from the app's own page: same origin, with the cookie, never cached.
function mountRequest(basePath?: string, fetcher?: { (input: URL | RequestInfo, init?: RequestInit | undefined): Promise<Response>; (input: string | URL | Request, init?: RequestInit | undefined): Promise<Response>; }): SynqMountRequestSynqClientPlugin
Interface. A browser plugin: actions over its server plugin's routes (defineSynqPlugin), which
interface SynqClientPlugin<Id extends string = string, Actions = unknown> {
readonly id: Id;
actions(request: SynqMountRequest): Actions;
}SynqMountRequest
Type. Calls the app's route mount: request('session'), request('account/v1/profile', { method: 'PATCH',... }).
type SynqMountRequest = (path: string, init?: RequestInit) => Promise<Response>;@synqauth/nextjs/config
defineSynqConfig
Function. Declares the app's Synq configuration: SYNQ_* environment variables fill in whatever it leaves out.
function defineSynqConfig<const T extends SynqAuthOptions>(options: T): TSynqAuthOptions
Interface. What synqAuth() and defineSynqConfig() take. Every option the
environment can give (SYNQ_*) is optional here; an option given wins.
interface SynqAuthOptions {
issuer?: string;
clientId?: string;
clientSecret?: string;
appUrl?: string;
sessionSecret?: string;
previousSessionSecrets?: readonly string[];
basePath?: string;
resource?: string;
account?: boolean;
scope?: string;
postLogoutRedirectUri?: string;
store?: SynqSessionStore;
allowSingleProcessCookieMode?: boolean;
sessionMaxAge?: number;
refreshLeewaySeconds?: number;
plugins?: readonly SynqPlugin[];
fetch?: typeof fetch;
clientAddress?: (request: Request) => string | undefined;
}See every package.