@gw31415/hono-oidc-simple
Version:
Simplifies the implementation of OIDC auth in Hono
207 lines (206 loc) • 7.22 kB
TypeScript
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 {};