yatta/oauth
OAuth 2.0: code + PKCE, client credentials, rotating refresh.
10 exported symbols and 43 members, read from src/func/oauth.ts.
Construct
clientsFromEnv
functionRead `OAUTH_CLIENTS` — a JSON list — into client inputs.
A bad entry is skipped with a warning instead of taking the process down: one mistyped redirect URI used to discard the good clients next to it, and the failure surfaced only as "invalid_client" at runtime.
clientsFromEnv(env: Record<string, string | undefined>): OAuthClientInput[]- env
- Usually `process.env`.
createOAuthServer
functionBuild an OAuth 2.0 authorization server.
Mount the three handlers on `/oauth/authorize`, `/oauth/token` and `/oauth/revoke`. The wire format is plain form-encoded HTTP, so the handlers take and return `Request`/`Response` directly.
createOAuthServer(options: OAuthServerOptions)MemoryOAuthStore
classIn-memory store. Fine for one server, and for tests.
Nothing survives a restart: issued tokens stop working and registered clients have to be registered again. Pass your own `store` to change that, and keep the write in that store out of the check-then-write window.
class MemoryOAuthStore implements OAuthStore10 members
clientspropertyclients:codespropertycodes:tokenspropertytokens:saveClientsaveClient(client: OAuthClient): voidgetClientgetClient(id: string): OAuthClient | undefinedsaveCodesaveCode(code: AuthCode): voidgetCodegetCode(codeHash: string): AuthCode | undefinedsaveTokensaveToken(token: OAuthTokenRecord): voidgetTokengetToken(tokenHash: string): OAuthTokenRecord | undefinedsweepsweep(now: number): void
Types
IdTokenIssuer
interfaceBuilds the OIDC ID token for a token reply.
Return null when there is no identity to sign (the user is gone, or the scope has no "openid"). `createOIDC` supplies one of these; a code exchange fails if it throws, and a refresh leaves the token out rather than stranding a grant whose old refresh token is already spent.
interface IdTokenIssuer1 member
[call]call(args: { clientId: string; userId: string; scope: string[]; nonce?: string; }): Promise<string | null> | string | null
OAuthClient
interfaceA registered OAuth client.
`secretHash` is empty for a public client — a mobile or browser app that cannot keep a secret. Public clients must use PKCE, because nothing else proves the code came back to whoever started the flow.
interface OAuthClient5 members
idpropertyid: stringsecretHashpropertysecretHash: stringredirectUrispropertyredirectUris: string[]namepropertyname?: stringallowedScopespropertyallowedScopes?: string[]
OAuthClientInput
interfaceWhat `registerClient` takes.
The secret is handed over in the clear exactly once, here; only its SHA-256 hash is kept. There is no way to read it back, which is why registering a client is a startup job rather than an API.
interface OAuthClientInput5 members
idpropertyid: stringsecretpropertysecret?: stringredirectUrispropertyredirectUris: string[]namepropertyname?: stringallowedScopespropertyallowedScopes?: string[]
OAuthServerOptions
interfaceinterface OAuthServerOptions12 members
issuerpropertyissuer: stringstorepropertystore?: OAuthStoreclientspropertyclients?: OAuthClientInput[]resolveUserpropertyresolveUser?: (req: Request) => Promise<string | null>accessTokenTtlSecpropertyaccessTokenTtlSec?: numberrefreshTokenTtlSecpropertyrefreshTokenTtlSec?: numbercodeTtlSecpropertycodeTtlSec?: numberissueIdTokenpropertyissueIdToken?: IdTokenIssuerscopespropertyscopes?: string[]requirePkcepropertyrequirePkce?: booleanallowPlainPkcepropertyallowPlainPkce?: booleanapprovepropertyapprove?: (info: { userId: string; client: OAuthClient; scope: string[]; }) => Promise<boolean> | boolean
OAuthStore
interfaceWhere clients, codes and tokens live.
Every method is synchronous by design: a check and its matching write must not be separated by an `await`, or two simultaneous requests can both spend the same code. A persistent store should therefore keep its state in memory and write through, not read from disk on each call.
interface OAuthStore7 members
saveClientsaveClient(client: OAuthClient): voidgetClientgetClient(id: string): OAuthClient | undefinedsaveCodesaveCode(code: AuthCode): voidgetCodegetCode(codeHash: string): AuthCode | undefinedsaveTokensaveToken(token: OAuthTokenRecord): voidgetTokengetToken(tokenHash: string): OAuthTokenRecord | undefinedsweepsweep(now: number): void?
OAuthTokenInfo
interfaceWhat `getAccessToken` returns for a live token.
interface OAuthTokenInfo3 members
userIdpropertyuserId: string | nullclientIdpropertyclientId: stringscopepropertyscope: string[]
OAuthServer
typeThe object `createOAuthServer` returns.
type OAuthServer = ReturnType<typeof createOAuthServer>AuthConfig or JobPayload — declaring your schema once is enough for the rest to follow. See Typed keys.