UNPKG

@gw31415/hono-oidc-simple

Version:

Simplifies the implementation of OIDC auth in Hono

207 lines (206 loc) 7.22 kB
import type { Context } from "hono"; import type { Handler, MiddlewareHandler } from "hono/types"; import type { SignatureAlgorithm } from "hono/utils/jwt/jwa"; import type { SignatureKey } from "hono/utils/jwt/jws"; /** Not-null type */ type NonNull = Record<never, never>; type AnyRecord<T = unknown> = Record<keyof any, T>; /** Custom claims for JWT tokens */ type CustomClaims = { [key: Exclude<string, "exp">]: NonNull | undefined; }; /** * Metadata for an OpenID Connect Issuer. * @template Issuer Union of the const-strings that represent Issuer URLs. */ interface AbstractIssuerMetadata<IU extends string> { /** OpenID Connect Issuer */ issuer: IU; /** OpenID Connect authentication endpoint */ authEndpoint: string; /** OpenID Connect token endpoint */ tokenEndpoint: string; /** OpenID Connect token revocation endpoint */ tokenRevocationEndpoint: string; /** OpenID Connect client ID */ clientId: string; /** OpenID Connect client secret */ clientSecret: string; /** OpenID Connect scopes */ scopes: string[]; } /** * Options for local JWT signing. */ export interface LocalJwtOptions { /** Private key for signing */ privateKey: SignatureKey; /** Signature algorithm */ alg?: SignatureAlgorithm; /** Validity period (in milliseconds) */ maxAge: number; } /** * Metadata for an OpenID Connect Issuer. * @template I Union of the const-strings that represent Issuer URLs. */ export type IssuerMetadata<C extends CustomClaims, IU extends string> = (AbstractIssuerMetadata<IU> & { /** Indicates if the Issuer supports refresh tokens */ useLocalJwt: true; /** Options for creating custom JWT when no refresh token is available */ localJwtOptions: LocalJwtOptions; /** Specify how Claims are generated using token and context */ createClaims: (c: Context, tokens: RefreshTokenGetter) => C | undefined | Promise<C | undefined>; }) | (AbstractIssuerMetadata<IU> & { /** Indicates if the Issuer supports refresh tokens */ useLocalJwt: false; /** Specify how Claims are generated using token and context */ createClaims: (c: Context, tokens: TokenGetter) => C | undefined | Promise<C | undefined>; }); /** * Options for OpenID Connect. * @template C Custom claims for JWT tokens * @template IU Union of the const-strings that represent Issuer URLs. */ export interface OIDCOptions<C extends CustomClaims, IU extends string> { /** Issuer metadata */ issuers: IssuerMetadata<C, IU>[]; /** Function to get the Issuer URL */ getIssUrl: (c: Context) => IU | Promise<IU> | undefined; /** Client-side token store */ clientSideTokenStore: TokenStore; } /** * Refresh token setter. */ interface RefreshTokenSetter { setRefreshToken(c: Context, token: string | undefined): void | Promise<void>; } /** * ID token setter. */ interface IDTokenSetter { setIDToken(c: Context, token: string | undefined): void | Promise<void>; } /** * ID token getter. */ interface IDTokenGetter { getIDToken(c: Context): string | undefined | Promise<string | undefined>; } /** * Refresh token getter. */ interface RefreshTokenGetter { getRefreshToken(c: Context): string | undefined | Promise<string | undefined>; } /** * ID token & refresh token setter. */ type TokenSetter = IDTokenSetter & RefreshTokenSetter; /** * ID token & refresh token getter. */ type TokenGetter = IDTokenGetter & RefreshTokenGetter; /** * ID token & refresh token getter and setter. */ export type TokenStore = TokenGetter & TokenSetter; /** * Get type of OIDC */ type OIDCManagerType<T> = T extends OIDCManager<CustomClaims, string> ? T : T extends { __oidc: infer U; } & AnyRecord ? OIDCManagerType<U> : T extends { Variables: infer U; } & AnyRecord ? OIDCManagerType<U> : T extends MiddlewareHandler<infer U> ? OIDCManagerType<U> : T extends OIDCSetupResult<infer C, infer IU> ? OIDCManager<C, IU> : never; /** * Get type of OIDC Custom Claims */ export type ClaimsType<T> = OIDCManagerType<T> extends OIDCManager<infer C, string> ? C : T extends IssuerMetadata<infer C, string> ? C : T extends OIDCOptions<infer C, string> ? C : T extends CustomClaims ? T : never; /** * Get type of OIDC Issuer URL */ export type IssuerType<T> = OIDCManagerType<T> extends OIDCManager<CustomClaims, infer IU> ? IU : T extends IssuerMetadata<CustomClaims, infer IU> ? IU : T extends OIDCOptions<CustomClaims, infer IU> ? IU : T extends string ? T : never; export type OIDCMiddlewareType<T> = T extends OIDCMiddleware<CustomClaims> ? T : ClaimsType<T> extends CustomClaims ? OIDCMiddleware<ClaimsType<T>> : never; type OIDCEnv<C extends CustomClaims> = { Variables: { claims: C | undefined; } & AnyRecord; }; type OIDCMiddleware<C extends CustomClaims> = MiddlewareHandler<OIDCEnv<C>>; type OIDCHandler<C extends CustomClaims> = Handler<OIDCEnv<C>>; /** * @template C Custom claims for JWT tokens * @template IU Union of the const-strings that represent Issuer URLs. * @template P Path parameters * @template I Input */ export interface OIDCSetupResult<C extends CustomClaims, IU extends string> { /** * Login handler for OpenID Connect. * @param iss Issuer URL * @param callback Callback function * @returns Handler */ loginHandler: (iss: IU, callback: (res: { type: "OK"; claims: C; } | { type: "ERR"; error: "OAuthServerError"; } | { type: "ERR"; error: "Unauthorized"; }, ...args: Parameters<OIDCHandler<C>>) => ReturnType<OIDCHandler<C>>) => OIDCHandler<C>; /** * Middleware to obtain claims from OpenID Connect. */ useClaims: OIDCMiddleware<C>; /** * Logout handler for OpenID Connect. * @param callback Callback function * @returns Handler */ logoutHandler: (callback: Handler) => Handler; } export declare function OIDC<C extends CustomClaims, IU extends string>(opts: OIDCOptions<C, IU> | ((c: Context) => OIDCOptions<C, IU> | Promise<OIDCOptions<C, IU>>)): OIDCSetupResult<C, IU>; /** * Internal OpenID Connect client. * @template C Custom claims for JWT tokens * @template IU Union of the const-strings that represent Issuer URLs. */ declare class OIDCManager<C extends CustomClaims, IU extends string> { #private; private constructor(); /** * Create an OIDC client. * @param c Context * @param opts OIDC options * @returns OIDC client */ static create<C extends CustomClaims, IU extends string>(c: Context, opts: OIDCOptions<C, IU>): Promise<OIDCManager<C, IU>>; /** * Manually Login with OpenID Connect. * @param c Context * @param issurl OpenID Connect Issuer URL * @returns Login result. If the login is successful, the claims are * returned. */ login(c: Context, issurl: IU): Promise<{ type: "OK"; claims: C; } | { type: "ERR"; error: "OAuthServerError"; } | { type: "ERR"; error: "Unauthorized"; } | { type: "RESPONSE"; response: Response; }>; getClaims(c: Context): Promise<C | undefined>; logout(c: Context): Promise<void>; } export {};