UNPKG

@adonisjs/auth

Version:

Official authentication provider for Adonis framework

636 lines (635 loc) 22.2 kB
/// <reference types="@adonisjs/application/build/adonis-typings/application" /> declare module '@ioc:Adonis/Addons/Auth' { import { DateTime } from 'luxon'; import { HashersList } from '@ioc:Adonis/Core/Hash'; import { QueryClientContract } from '@ioc:Adonis/Lucid/Database'; import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; import { ApplicationContract } from '@ioc:Adonis/Core/Application'; import { DatabaseQueryBuilderContract } from '@ioc:Adonis/Lucid/Database'; import { LucidModel, LucidRow, ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm'; /** * Unwraps user from the provider user */ type UnWrapProviderUser<T> = T extends ProviderUserContract<any> ? Exclude<T['user'], null> : T; /** * Unwraps awaited type from Promise */ type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T; /** * Returns the real user from the provider user */ export type GetProviderRealUser<Provider extends keyof ProvidersList> = UnWrapProviderUser<Awaited<ReturnType<ProvidersList[Provider]['implementation']['getUserFor']>>>; /** * Provider user works as a bridge between the provider real user * and the guard. It is never exposed to the end-user. */ export interface ProviderUserContract<User extends any> { user: User | null; getId(): string | number | null; verifyPassword: (plainPassword: string) => Promise<boolean>; getRememberMeToken(): string | null; setRememberMeToken(token: string): void; } /** * The interface that every provider must implement */ export interface UserProviderContract<User extends any> { /** * Return an instance of the user wrapped inside the Provider user contract */ getUserFor(user: User): Promise<ProviderUserContract<User>>; /** * Find a user using the primary key value */ findById(id: string | number): Promise<ProviderUserContract<User>>; /** * Find a user by searching for their uids */ findByUid(uid: string): Promise<ProviderUserContract<User>>; /** * Find a user using the remember me token */ findByRememberMeToken(userId: string | number, token: string): Promise<ProviderUserContract<User>>; /** * Update remember token */ updateRememberMeToken(authenticatable: ProviderUserContract<User>): Promise<void>; } /** * Shape of the token sent to/read from the tokens provider */ export interface ProviderTokenContract { /** * Persisted token value. It is a sha256 hash */ tokenHash: string; /** * Token name */ name: string; /** * Token type */ type: string; /** * UserId for which the token was saved */ userId: string | number; /** * Expiry date */ expiresAt?: DateTime; /** * All other token details */ meta?: any; } /** * Token providers provides the API to create/fetch and delete tokens * for a given user. Any token based implementation can use token * providers, given they only store a single token. */ export interface TokenProviderContract { /** * Define a custom connection for the driver in use */ setConnection(connection: any): this; /** * Saves the token to some persistance storage and returns an lookup * id. We introduced the concept of lookup ids, since lookups by * cryptographic tokens can have performance impacts on certain * databases. * * Also note that the return lookup id is also prepended to the raw * token, so that we can later extract the id for reads. The * real message is to keep the lookup ids small. */ write(token: ProviderTokenContract): Promise<string>; /** * Find token using the lookup id or the token value */ read(lookupId: string, token: string, type: string): Promise<ProviderTokenContract | null>; /** * Delete token using the lookup id or the token value */ destroy(lookupId: string, type: string): Promise<void>; } /** * Config for the database token provider */ export type DatabaseTokenProviderConfig = { driver: 'database'; table: string; foreignKey?: string; connection?: string; type?: string; }; /** * Config for the redis token provider */ export type RedisTokenProviderConfig = { driver: 'redis'; redisConnection: string; foreignKey?: string; type?: string; }; /** * The shape of the user model accepted by the Lucid provider. The model * must have `password` and `rememberMeToken` attributes. */ export type LucidProviderModel = LucidModel & { findForAuth?: <T extends LucidModel>(this: T, uids: string[], value: any) => Promise<InstanceType<T>>; } & { new (): LucidRow & { password?: string; rememberMeToken?: string | null; }; }; /** * Shape of the lucid provider user builder. It must return [[ProviderUserContract]] */ export interface LucidProviderUserBuilder<User extends LucidProviderModel> { new (user: InstanceType<User> | null, config: LucidProviderConfig<User>, ...args: any[]): ProviderUserContract<InstanceType<User>>; } /** * Lucid provider */ export interface LucidProviderContract<User extends LucidProviderModel> extends UserProviderContract<InstanceType<User>> { /** * Define a custom connection for all the provider queries */ setConnection(connection: string | QueryClientContract): this; /** * Before hooks */ before(event: 'findUser', callback: (query: ModelQueryBuilderContract<User>) => Promise<void>): this; /** * After hooks */ after(event: 'findUser', callback: (user: InstanceType<User>) => Promise<void>): this; } /** * The config accepted by the Lucid provider */ export type LucidProviderConfig<User extends LucidProviderModel> = { driver: 'lucid'; model: () => Promise<User> | Promise<{ default: User; }>; uids: (keyof InstanceType<User>)[]; identifierKey: string; connection?: string; hashDriver?: keyof HashersList; user?: () => Promise<LucidProviderUserBuilder<User>> | Promise<{ default: LucidProviderUserBuilder<User>; }>; }; /** * Shape of the row returned by the database provider. The table must have `password` * and `remember_me_token` columns. */ export type DatabaseProviderRow = { password?: string; remember_me_token?: string; [key: string]: any; }; /** * Shape of database provider user builder. It must always returns [[ProviderUserContract]] */ export interface DatabaseProviderUserBuilder { new (user: DatabaseProviderRow | null, config: DatabaseProviderConfig, ...args: any[]): ProviderUserContract<DatabaseProviderRow>; } /** * Database provider */ export interface DatabaseProviderContract<User extends DatabaseProviderRow> extends UserProviderContract<User> { /** * Define a custom connection for all the provider queries */ setConnection(connection: string | QueryClientContract): this; /** * Before hooks */ before(event: 'findUser', callback: (query: DatabaseQueryBuilderContract) => Promise<void>): this; /** * After hooks */ after(event: 'findUser', callback: (user: DatabaseProviderRow) => Promise<void>): this; } /** * The config accepted by the Database provider */ export type DatabaseProviderConfig = { driver: 'database'; uids: string[]; usersTable: string; identifierKey: string; connection?: string; hashDriver?: keyof HashersList; user?: () => Promise<DatabaseProviderUserBuilder> | Promise<{ default: DatabaseProviderUserBuilder; }>; }; /** * Request data a guard client can set when making the * testing request */ export type ClientRequestData = { session?: Record<string, any>; headers?: Record<string, any>; cookies?: Record<string, any>; }; /** * The authentication clients should follow this interface */ export interface GuardClientContract<Provider extends keyof ProvidersList> { /** * Login a user */ login(user: GetProviderRealUser<Provider>, ...args: any[]): Promise<ClientRequestData>; /** * Logout user */ logout(user: GetProviderRealUser<Provider>): Promise<void>; } export interface GuardContract<Provider extends keyof ProvidersList, Guard extends keyof GuardsList> { name: Guard; /** * Reference to the guard config */ config: GuardsList[Guard]['config']; /** * Reference to the logged in user. */ user?: GetProviderRealUser<Provider>; /** * Find if the user has been logged out in the current request */ isLoggedOut: boolean; /** * A boolean to know if user is a guest or not. It is * always opposite of [[isLoggedIn]] */ isGuest: boolean; /** * A boolean to know if user is logged in or not */ isLoggedIn: boolean; /** * A boolean to know if user is retrieved by authenticating * the current request or not. */ isAuthenticated: boolean; /** * Whether or not the authentication has been attempted * for the current request */ authenticationAttempted: boolean; /** * Reference to the provider for looking up the user */ provider: ProvidersList[Provider]['implementation']; /** * Verify user credentials. */ verifyCredentials(uid: string, password: string): Promise<GetProviderRealUser<Provider>>; /** * Attempt to verify user credentials and perform login */ attempt(uid: string, password: string, ...args: any[]): Promise<any>; /** * Login a user without any verification */ login(user: GetProviderRealUser<Provider>, ...args: any[]): Promise<any>; /** * Login a user using their id */ loginViaId(id: string | number, ...args: any[]): Promise<any>; /** * Attempts to authenticate the user for the current HTTP request. An exception * is raised when unable to do so */ authenticate(): Promise<GetProviderRealUser<Provider>>; /** * Attempts to authenticate the user for the current HTTP request and supresses * exceptions raised by the [[authenticate]] method and returns a boolean */ check(): Promise<boolean>; /** * Logout user */ logout(...args: any[]): Promise<void>; /** * Serialize guard to JSON */ toJSON(): any; } /** * Shape of data emitted by the login event */ export type SessionLoginEventData<Provider extends keyof ProvidersList> = { name: string; user: GetProviderRealUser<Provider>; ctx: HttpContextContract; token: string | null; }; /** * Shape of data emitted by the authenticate event */ export type SessionAuthenticateEventData<Provider extends keyof ProvidersList> = { name: string; user: GetProviderRealUser<Provider>; ctx: HttpContextContract; viaRemember: boolean; }; /** * Shape of the session guard */ export interface SessionGuardContract<Provider extends keyof ProvidersList, Name extends keyof GuardsList> extends GuardContract<Provider, Name> { /** * A boolean to know if user is loggedin via remember me token or not. */ viaRemember: boolean; /** * Attempt to verify user credentials and perform login */ attempt(uid: string, password: string, remember?: boolean): Promise<any>; /** * Login a user without any verification */ login(user: GetProviderRealUser<Provider>, remember?: boolean): Promise<any>; /** * Login a user using their id */ loginViaId(id: string | number, remember?: boolean): Promise<any>; /** * Logout user */ logout(renewRememberToken?: boolean): Promise<void>; } /** * Session client to login users during tests */ export interface SessionClientContract<Provider extends keyof ProvidersList> extends GuardClientContract<Provider> { } /** * Shape of session driver config. */ export type SessionGuardConfig<Provider extends keyof ProvidersList> = { driver: 'session'; provider: ProvidersList[Provider]['config']; }; /** * Shape of data emitted by the authenticate event */ export type BasicAuthAuthenticateEventData<Provider extends keyof ProvidersList> = { name: string; user: GetProviderRealUser<Provider>; ctx: HttpContextContract; }; /** * Shape of the basic auth guard */ export interface BasicAuthGuardContract<Provider extends keyof ProvidersList, Name extends keyof GuardsList> extends Omit<GuardContract<Provider, Name>, 'attempt' | 'login' | 'loginViaId' | 'logout'> { } /** * Basic auth client to login users during tests */ export interface BasicAuthClientContract<Provider extends keyof ProvidersList> extends GuardClientContract<Provider> { } /** * Shape of basic auth guard config. */ export type BasicAuthGuardConfig<Provider extends keyof ProvidersList> = { driver: 'basic'; realm?: string; provider: ProvidersList[Provider]['config']; }; /** * Opaque token is generated during the login call by the OpaqueTokensGuard */ export interface OpaqueTokenContract<User extends any> { /** * Always a bearer token */ type: 'bearer'; /** * The user for which the token was generated */ user: User; /** * Date/time when the token will be expired */ expiresAt?: DateTime; /** * Time in seconds until the token is valid */ expiresIn?: number; /** * Any meta-data attached with the token */ meta: any; /** * Token name */ name: string; /** * Token public value */ token: string; /** * Token hash (persisted to the db as well) */ tokenHash: string; /** * Serialize token */ toJSON(): { type: 'bearer'; token: string; expires_at?: string; expires_in?: number; }; } /** * Login options */ export type OATLoginOptions = { name?: string; expiresIn?: number | string; } & { [key: string]: any; }; /** * Shape of data emitted by the login event */ export type OATLoginEventData<Provider extends keyof ProvidersList> = { name: string; user: GetProviderRealUser<Provider>; ctx: HttpContextContract; token: OpaqueTokenContract<GetProviderRealUser<Provider>>; }; /** * Shape of the data emitted by the authenticate event */ export type OATAuthenticateEventData<Provider extends keyof ProvidersList> = { name: string; user: GetProviderRealUser<Provider>; ctx: HttpContextContract; token: ProviderTokenContract; }; /** * Shape of the OAT guard */ export interface OATGuardContract<Provider extends keyof ProvidersList, Name extends keyof GuardsList> extends GuardContract<Provider, Name> { token?: ProviderTokenContract; tokenProvider: TokenProviderContract; /** * Attempt to verify user credentials and perform login */ attempt(uid: string, password: string, options?: OATLoginOptions): Promise<OpaqueTokenContract<GetProviderRealUser<Provider>>>; /** * Login a user without any verification */ login(user: GetProviderRealUser<Provider>, options?: OATLoginOptions): Promise<OpaqueTokenContract<GetProviderRealUser<Provider>>>; /** * Generate token for a user without any verification */ generate(user: GetProviderRealUser<Provider>, options?: OATLoginOptions): Promise<OpaqueTokenContract<GetProviderRealUser<Provider>>>; /** * Alias for logout */ revoke(): Promise<void>; /** * Login a user using their id */ loginViaId(id: string | number, options?: OATLoginOptions): Promise<OpaqueTokenContract<GetProviderRealUser<Provider>>>; } /** * Oat guard to login users during tests */ export interface OATClientContract<Provider extends keyof ProvidersList> extends GuardClientContract<Provider> { login(user: GetProviderRealUser<Provider>, options?: OATLoginOptions): Promise<ClientRequestData>; } /** * Shape of OAT guard config. */ export type OATGuardConfig<Provider extends keyof ProvidersList> = { /** * Driver name is always constant */ driver: 'oat'; /** * Provider for managing tokens */ tokenProvider: DatabaseTokenProviderConfig | RedisTokenProviderConfig; /** * User provider */ provider: ProvidersList[Provider]['config']; }; /** * List of providers mappings used by the app. Using declaration * merging, one must extend this interface. * * MUST BE SET IN THE USER LAND. * * Example: * * lucid: { * config: LucidProviderConfig<any>, * implementation: LucidProviderContract<any>, * } * */ export interface ProvidersList { } /** * List of guards mappings used by the app. Using declaration * merging, one must extend this interface. * * MUST BE SET IN THE USER LAND. * * Example: * * session: { * config: SessionGuardConfig<'lucid'>, * implementation: SessionGuardContract<'lucid'>, * client: SessionClientContract<'lucid'>, * } * */ export interface GuardsList { } /** * Shape of config accepted by the Auth module. It relies on the * [[GuardsList]] interface */ export type AuthConfig = { guard: keyof GuardsList; guards: { [P in keyof GuardsList]: GuardsList[P]['config']; }; }; /** * Instance of the auth contract. The `use` method can be used to obtain * an instance of a given guard mapping for a single HTTP request */ export interface AuthContract extends GuardContract<keyof ProvidersList, keyof GuardsList> { /** * The default guard for the current request */ defaultGuard: string; /** * Use a given guard */ use(): GuardContract<keyof ProvidersList, keyof GuardsList>; use<K extends keyof GuardsList>(guard: K): GuardsList[K]['implementation']; } /** * Shape of the callback accepted to add new user providers */ export type ExtendProviderCallback = (auth: AuthManagerContract, mapping: string, config: any) => UserProviderContract<any>; /** * Shape of the callback accepted to add new guards */ export type ExtendGuardCallback = (auth: AuthManagerContract, mapping: string, config: any, provider: UserProviderContract<any>, ctx: HttpContextContract) => GuardContract<keyof ProvidersList, keyof GuardsList>; /** * Shape of the callback accepted to add custom testing * clients */ export type ExtendClientCallback = (auth: AuthManagerContract, mapping: string, config: any, provider: UserProviderContract<any>) => GuardClientContract<keyof ProvidersList>; /** * Shape of the auth manager to register custom drivers and providers and * make instances of them */ export interface AuthManagerContract { application: ApplicationContract; /** * The default guard */ defaultGuard: string; /** * Returns the instance of [[AuthContract]] for a given HTTP request */ getAuthForRequest(ctx: HttpContextContract): AuthContract; /** * Make instance of a mapping */ makeMapping(ctx: HttpContextContract, mapping: string): GuardContract<keyof ProvidersList, keyof GuardsList>; makeMapping<K extends keyof GuardsList>(ctx: HttpContextContract, mapping: K): GuardsList[K]['implementation']; /** * Returns an instance of the auth client for a given * mapping */ client(mapping: string): GuardClientContract<keyof ProvidersList>; /** * Extend by adding custom providers, guards and client */ extend(type: 'provider', provider: string, callback: ExtendProviderCallback): void; extend(type: 'guard', guard: string, callback: ExtendGuardCallback): void; extend(type: 'client', guard: string, callback: ExtendClientCallback): void; } const AuthManager: AuthManagerContract; export default AuthManager; }