import { SubjectSchema } from "./subject.js"; import type { v1 } from "@standard-schema/spec"; import { InvalidAccessTokenError, InvalidAuthorizationCodeError, InvalidRefreshTokenError } from "./error.js"; /** * The well-known information for an OAuth 2.0 authorization server. * @internal */ export interface WellKnown { /** * The URI to the JWKS endpoint. */ jwks_uri: string; /** * The URI to the token endpoint. */ token_endpoint: string; /** * The URI to the authorization endpoint. */ authorization_endpoint: string; } /** * The tokens returned by the auth server. */ export interface Tokens { /** * The access token. */ access: string; /** * The refresh token. */ refresh: string; /** * The number of seconds until the access token expires. */ expiresIn: number; } interface ResponseLike { json(): Promise; ok: Response["ok"]; } type FetchLike = (...args: any[]) => Promise; /** * The challenge that you can use to verify the code. */ export type Challenge = { /** * The state that was sent to the redirect URI. */ state: string; /** * The verifier that was sent to the redirect URI. */ verifier?: string; }; /** * Configure the client. */ export interface ClientInput { /** * The client ID. This is just a string to identify your app. * * If you have a web app and a mobile app, you want to use different client IDs both. * * @example * ```ts * { * clientID: "my-client" * } * ``` */ clientID: string; /** * The URL of your OpenAuth server. * * @example * ```ts * { * issuer: "https://auth.myserver.com" * } * ``` */ issuer?: string; /** * Optionally, override the internally used fetch function. * * This is useful if you are using a polyfilled fetch function in your application and you * want the client to use it too. */ fetch?: FetchLike; } export interface AuthorizeOptions { /** * Enable the PKCE flow. This is for SPA apps. * * ```ts * { * pkce: true * } * ``` * * @default false */ pkce?: boolean; /** * The provider you want to use for the OAuth flow. * * ```ts * { * provider: "google" * } * ``` * * If no provider is specified, the user is directed to a page where they can select from the * list of configured providers. * * If there's only one provider configured, the user will be redirected to that. */ provider?: string; } export interface AuthorizeResult { /** * The challenge that you can use to verify the code. This is for the PKCE flow for SPA apps. * * This is an object that you _stringify_ and store it in session storage. * * ```ts * sessionStorage.setItem("challenge", JSON.stringify(challenge)) * ``` */ challenge: Challenge; /** * The URL to redirect the user to. This starts the OAuth flow. * * For example, for SPA apps. * * ```ts * location.href = url * ``` */ url: string; } /** * Returned when the exchange is successful. */ export interface ExchangeSuccess { /** * This is always `false` when the exchange is successful. */ err: false; /** * The access and refresh tokens. */ tokens: Tokens; } /** * Returned when the exchange fails. */ export interface ExchangeError { /** * The type of error that occurred. You can handle this by checking the type. * * @example * ```ts * import { InvalidAuthorizationCodeError } from "@openauthjs/openauth/error" * * console.log(err instanceof InvalidAuthorizationCodeError) *``` */ err: InvalidAuthorizationCodeError; } export interface RefreshOptions { /** * Optionally, pass in the access token. */ access?: string; } /** * Returned when the refresh is successful. */ export interface RefreshSuccess { /** * This is always `false` when the refresh is successful. */ err: false; /** * Returns the refreshed tokens only if they've been refreshed. * * If they are still valid, this will be `undefined`. */ tokens?: Tokens; } /** * Returned when the refresh fails. */ export interface RefreshError { /** * The type of error that occurred. You can handle this by checking the type. * * @example * ```ts * import { InvalidRefreshTokenError } from "@openauthjs/openauth/error" * * console.log(err instanceof InvalidRefreshTokenError) *``` */ err: InvalidRefreshTokenError | InvalidAccessTokenError; } export interface VerifyOptions { /** * Optionally, pass in the refresh token. * * If passed in, this will automatically refresh the access token if it has expired. */ refresh?: string; /** * @internal */ issuer?: string; /** * @internal */ audience?: string; /** * Optionally, override the internally used fetch function. * * This is useful if you are using a polyfilled fetch function in your application and you * want the client to use it too. */ fetch?: FetchLike; } export interface VerifyResult { /** * This is always `undefined` when the verify is successful. */ err?: undefined; /** * Returns the refreshed tokens only if they’ve been refreshed. * * If they are still valid, this will be undefined. */ tokens?: Tokens; /** * @internal */ aud: string; /** * The decoded subjects from the access token. * * Has the same shape as the subjects you defined when creating the issuer. */ subject: { [type in keyof T]: { type: type; properties: v1.InferOutput; }; }[keyof T]; } /** * Returned when the verify call fails. */ export interface VerifyError { /** * The type of error that occurred. You can handle this by checking the type. * * @example * ```ts * import { InvalidRefreshTokenError } from "@openauthjs/openauth/error" * * console.log(err instanceof InvalidRefreshTokenError) *``` */ err: InvalidRefreshTokenError | InvalidAccessTokenError; } /** * An instance of the OpenAuth client contains the following methods. */ export interface Client { /** * Start the autorization flow. For example, in SSR sites. * * ```ts * const { url } = await client.authorize(, "code") * ``` * * This takes a redirect URI and the type of flow you want to use. The redirect URI is the * location where the user will be redirected to after the flow is complete. * * Supports both the _code_ and _token_ flows. We recommend using the _code_ flow as it's more * secure. * * :::tip * This returns a URL to redirect the user to. This starts the OAuth flow. * ::: * * This returns a URL to the auth server. You can redirect the user to the URL to start the * OAuth flow. * * For SPA apps, we recommend using the PKCE flow. * * ```ts {4} * const { challenge, url } = await client.authorize( * , * "code", * { pkce: true } * ) * ``` * * This returns a redirect URL and a challenge that you need to use later to verify the code. */ authorize(redirectURI: string, response: "code" | "token", opts?: AuthorizeOptions): Promise; /** * Exchange the code for access and refresh tokens. * * ```ts * const exchanged = await client.exchange(, ) * ``` * * You call this after the user has been redirected back to your app after the OAuth flow. * * :::tip * For SSR sites, the code is returned in the query parameter. * ::: * * So the code comes from the query parameter in the redirect URI. The redirect URI here is * the one that you passed in to the `authorize` call when starting the flow. * * :::tip * For SPA sites, the code is returned through the URL hash. * ::: * * If you used the PKCE flow for an SPA app, the code is returned as a part of the redirect URL * hash. * * ```ts {4} * const exchanged = await client.exchange( * , * , * * ) * ``` * * You also need to pass in the previously stored challenge verifier. * * This method returns the access and refresh tokens. Or if it fails, it returns an error that * you can handle depending on the error. * * ```ts * import { InvalidAuthorizationCodeError } from "@openauthjs/openauth/error" * * if (exchanged.err) { * if (exchanged.err instanceof InvalidAuthorizationCodeError) { * // handle invalid code error * } * else { * // handle other errors * } * } * * const { access, refresh } = exchanged.tokens * ``` */ exchange(code: string, redirectURI: string, verifier?: string): Promise; /** * Refreshes the tokens if they have expired. This is used in an SPA app to maintain the * session, without logging the user out. * * ```ts * const next = await client.refresh() * ``` * * Can optionally take the access token as well. If passed in, this will skip the refresh * if the access token is still valid. * * ```ts * const next = await client.refresh(, { access: }) * ``` * * This returns the refreshed tokens only if they've been refreshed. * * ```ts * if (!next.err) { * // tokens are still valid * } * if (next.tokens) { * const { access, refresh } = next.tokens * } * ``` * * Or if it fails, it returns an error that you can handle depending on the error. * * ```ts * import { InvalidRefreshTokenError } from "@openauthjs/openauth/error" * * if (next.err) { * if (next.err instanceof InvalidRefreshTokenError) { * // handle invalid refresh token error * } * else { * // handle other errors * } * } * ``` */ refresh(refresh: string, opts?: RefreshOptions): Promise; /** * Verify the token in the incoming request. * * This is typically used for SSR sites where the token is stored in an HTTP only cookie. And * is passed to the server on every request. * * ```ts * const verified = await client.verify(, ) * ``` * * This takes the subjects that you had previously defined when creating the issuer. * * :::tip * If the refresh token is passed in, it'll automatically refresh the access token. * ::: * * This can optionally take the refresh token as well. If passed in, it'll automatically * refresh the access token if it has expired. * * ```ts * const verified = await client.verify(, , { refresh: }) * ``` * * This returns the decoded subjects from the access token. And the tokens if they've been * refreshed. * * ```ts * // based on the subjects you defined earlier * console.log(verified.subject.properties.userID) * * if (verified.tokens) { * const { access, refresh } = verified.tokens * } * ``` * * Or if it fails, it returns an error that you can handle depending on the error. * * ```ts * import { InvalidRefreshTokenError } from "@openauthjs/openauth/error" * * if (verified.err) { * if (verified.err instanceof InvalidRefreshTokenError) { * // handle invalid refresh token error * } * else { * // handle other errors * } * } * ``` */ verify(subjects: T, token: string, options?: VerifyOptions): Promise | VerifyError>; } /** * Create an OpenAuth client. * * @param input - Configure the client. */ export declare function createClient(input: ClientInput): Client; export {}; //# sourceMappingURL=client.d.ts.map