@travetto/auth-passport
Version:
Rest authentication integration support for the travetto framework
90 lines (78 loc) • 2.91 kB
text/typescript
import * as passport from 'passport';
import { Authenticator, Principal } from '@travetto/auth';
import { Request, Response } from '@travetto/rest';
import { LoginContextⲐ } from '@travetto/auth-rest/src/internal/types';
import { PassportAuthOptions, PassportUtil } from './util';
type SimplePrincipal = Omit<Principal, 'issuedAt' | 'expiresAt'>;
/**
* Authenticator via passport
*/
export class PassportAuthenticator<U> implements Authenticator<U, Principal, { req: Request, res: Response }> {
#strategyName: string;
#strategy: passport.Strategy;
#toPrincipal: (user: U) => SimplePrincipal;
#passportAuthenticateOptions: passport.AuthenticateOptions;
#extraOptions: PassportAuthOptions;
session = false;
/**
* Creating a new PassportAuthenticator
*
* @param strategyName Name of passport strategy
* @param strategy A passport strategy
* @param toPrincipal How to convert a user to an identity
* @param passportAuthenticateOptions Extra passport options
*/
constructor(
strategyName: string,
strategy: passport.Strategy,
toPrincipal: (user: U) => SimplePrincipal,
passportAuthenticateOptions: passport.AuthenticateOptions = {},
extraOptions: PassportAuthOptions = {}
) {
this.#strategyName = strategyName;
this.#strategy = strategy;
this.#toPrincipal = toPrincipal;
this.#passportAuthenticateOptions = passportAuthenticateOptions;
this.#extraOptions = extraOptions;
passport.use(this.#strategyName, this.#strategy);
}
/**
* Handler for auth context
* @param err A possible error from authentication
* @param user The authenticated user
*/
async #authHandler(err: Error | undefined, user: U): Promise<Principal> {
if (err) {
throw err;
} else {
// Remove profile fields from passport
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const du = user as (U & { _json?: unknown, _raw?: unknown, source?: unknown });
delete du._json;
delete du._raw;
delete du.source;
const p = this.#toPrincipal(user);
p.issuer ??= this.#strategyName;
return p;
}
}
/**
* Authenticate a request given passport config
* @param req The travetto request
* @param res The travetto response
*/
authenticate(user: U, { req, res }: { req: Request, res: Response }): Promise<Principal | undefined> {
return new Promise<Principal | undefined>((resolve, reject) => {
// Get the login context
req[LoginContextⲐ] = PassportUtil.getLoginContext(req);
const filter = passport.authenticate(this.#strategyName,
{
session: this.session,
...this.#passportAuthenticateOptions,
...PassportUtil.createLoginContext(req, this.#extraOptions)
},
(err, u) => this.#authHandler(err, u).then(resolve, reject));
filter(req, res);
});
}
}