Skip to content

Commit 84ed88f

Browse files
Feature to allow custom verify providers for individual authentication context (#27)
1 parent 5a6fd27 commit 84ed88f

14 files changed

+118
-71
lines changed

src/decorators/authenticate-user.decorator.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import {
2+
BindingKey,
23
Constructor,
34
MetadataInspector,
45
MethodDecoratorFactory,
56
} from '@loopback/context';
67
import {Request} from '@loopback/rest';
78

89
import {USER_AUTHENTICATION_METADATA_KEY} from '../keys';
10+
import {VerifyFunction} from '../strategies';
911
import {AuthenticationMetadata} from '../types';
1012

1113
/**
@@ -15,6 +17,7 @@ import {AuthenticationMetadata} from '../types';
1517
* like `Strategy.LOCAL`
1618
* @param options Extra options to be passed on
1719
* while instantiating strategy specific class
20+
* @param verifier Binding key for a custom verifier
1821
* @param authOptions Extra options to be passed on to `authenticate` method
1922
* of the strategy.
2023
* This is a creator function which should return an object with options.
@@ -26,13 +29,15 @@ export function authenticate(
2629
strategyName: string,
2730
options?: Object,
2831
authOptions?: (req: Request) => Object,
32+
verifier?: BindingKey<VerifyFunction.GenericAuthFn>,
2933
) {
3034
return MethodDecoratorFactory.createDecorator<AuthenticationMetadata>(
3135
USER_AUTHENTICATION_METADATA_KEY,
3236
{
3337
strategy: strategyName,
3438
options: options ?? {},
3539
authOptions: authOptions,
40+
verifier,
3641
},
3742
);
3843
}

src/strategies/passport/passport-azure-ad/azuread-auth-strategy-factory-provider.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
export interface AzureADAuthStrategyFactory {
1616
(
1717
options: IOIDCStrategyOptionWithoutRequest | IOIDCStrategyOptionWithRequest,
18+
verifierPassed?: VerifyFunction.AzureADAuthFn,
1819
): OIDCStrategy;
1920
}
2021

@@ -26,12 +27,15 @@ export class AzureADAuthStrategyFactoryProvider
2627
) {}
2728

2829
value(): AzureADAuthStrategyFactory {
29-
return (options) => this.getAzureADAuthStrategyVerifier(options);
30+
return (options, verifier) =>
31+
this.getAzureADAuthStrategyVerifier(options, verifier);
3032
}
3133

3234
getAzureADAuthStrategyVerifier(
3335
options: IOIDCStrategyOptionWithoutRequest | IOIDCStrategyOptionWithRequest,
36+
verifierPassed?: VerifyFunction.AzureADAuthFn,
3437
): OIDCStrategy {
38+
const verifyFn = verifierPassed ?? this.verifierAzureADAuth;
3539
if (options && options.passReqToCallback === true) {
3640
return new OIDCStrategy(
3741
options,
@@ -43,7 +47,7 @@ export class AzureADAuthStrategyFactoryProvider
4347
}
4448

4549
try {
46-
const user = await this.verifierAzureADAuth(profile, done, req);
50+
const user = await verifyFn(profile, done, req);
4751
if (!user) {
4852
throw new HttpErrors.Unauthorized(
4953
AuthErrorKeys.InvalidCredentials,
@@ -66,7 +70,7 @@ export class AzureADAuthStrategyFactoryProvider
6670
}
6771

6872
try {
69-
const user = await this.verifierAzureADAuth(profile, done);
73+
const user = await verifyFn(profile, done);
7074
if (!user) {
7175
throw new HttpErrors.Unauthorized(
7276
AuthErrorKeys.InvalidCredentials,

src/strategies/passport/passport-bearer/bearer-strategy-factory-provider.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import {VerifyFunction} from '../../types';
99
import {isEmpty} from 'lodash';
1010

1111
export interface BearerStrategyFactory {
12-
(options?: PassportBearer.IStrategyOptions): PassportBearer.Strategy;
12+
(
13+
options?: PassportBearer.IStrategyOptions,
14+
verifierPassed?: VerifyFunction.BearerFn,
15+
): PassportBearer.Strategy;
1316
}
1417

1518
export class BearerStrategyFactoryProvider
@@ -20,12 +23,15 @@ export class BearerStrategyFactoryProvider
2023
) {}
2124

2225
value(): BearerStrategyFactory {
23-
return (options) => this.getBearerStrategyVerifier(options);
26+
return (options, verifier) =>
27+
this.getBearerStrategyVerifier(options, verifier);
2428
}
2529

2630
getBearerStrategyVerifier(
2731
options?: PassportBearer.IStrategyOptions,
32+
verifierPassed?: VerifyFunction.BearerFn,
2833
): PassportBearer.Strategy {
34+
const verifyFn = verifierPassed ?? this.verifierBearer;
2935
if (options?.passReqToCallback) {
3036
return new PassportBearer.Strategy(
3137
options,
@@ -36,7 +42,7 @@ export class BearerStrategyFactoryProvider
3642
cb: (err: Error | null, user?: IAuthUser | false) => void,
3743
) => {
3844
try {
39-
const user = await this.verifierBearer(token, req);
45+
const user = await verifyFn(token, req);
4046
if (!user) {
4147
throw new HttpErrors.Unauthorized(AuthErrorKeys.TokenInvalid);
4248
}
@@ -56,7 +62,7 @@ export class BearerStrategyFactoryProvider
5662
cb: (err: Error | null, user?: IAuthUser | false) => void,
5763
) => {
5864
try {
59-
const user = await this.verifierBearer(token);
65+
const user = await verifyFn(token);
6066
if (!user) {
6167
throw new HttpErrors.Unauthorized(AuthErrorKeys.TokenInvalid);
6268
}
@@ -74,7 +80,7 @@ export class BearerStrategyFactoryProvider
7480
cb: (err: Error | null, user?: IAuthUser | false) => void,
7581
) => {
7682
try {
77-
const user = await this.verifierBearer(token);
83+
const user = await verifyFn(token);
7884
if (!user) {
7985
throw new HttpErrors.Unauthorized(
8086
AuthErrorKeys.InvalidCredentials,

src/strategies/passport/passport-bearer/bearer-token-verify.provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class BearerTokenVerifyProvider
1313
constructor() {}
1414

1515
value(): VerifyFunction.BearerFn {
16-
return async (token) => {
16+
return async (token: string) => {
1717
throw new HttpErrors.NotImplemented(
1818
`VerifyFunction.BearerFn is not implemented`,
1919
);

src/strategies/passport/passport-client-password/client-password-strategy-factory-provider.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {VerifyFunction} from '../../types';
1010
export interface ClientPasswordStrategyFactory {
1111
(
1212
options?: ClientPasswordStrategy.StrategyOptionsWithRequestInterface,
13+
verifierPassed?: VerifyFunction.OauthClientPasswordFn,
1314
): ClientPasswordStrategy.Strategy;
1415
}
1516

@@ -21,12 +22,15 @@ export class ClientPasswordStrategyFactoryProvider
2122
) {}
2223

2324
value(): ClientPasswordStrategyFactory {
24-
return (options) => this.getClientPasswordVerifier(options);
25+
return (options, verifier) =>
26+
this.getClientPasswordVerifier(options, verifier);
2527
}
2628

2729
getClientPasswordVerifier(
2830
options?: ClientPasswordStrategy.StrategyOptionsWithRequestInterface,
31+
verifierPassed?: VerifyFunction.OauthClientPasswordFn,
2932
): ClientPasswordStrategy.Strategy {
33+
const verifyFn = verifierPassed ?? this.verifier;
3034
if (options?.passReqToCallback) {
3135
return new ClientPasswordStrategy.Strategy(
3236
options,
@@ -39,7 +43,7 @@ export class ClientPasswordStrategyFactoryProvider
3943
cb: (err: Error | null, client?: IAuthClient | false) => void,
4044
) => {
4145
try {
42-
const client = await this.verifier(clientId, clientSecret, req);
46+
const client = await verifyFn(clientId, clientSecret, req);
4347
if (!client) {
4448
throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
4549
} else if (
@@ -65,7 +69,7 @@ export class ClientPasswordStrategyFactoryProvider
6569
cb: (err: Error | null, client?: IAuthClient | false) => void,
6670
) => {
6771
try {
68-
const client = await this.verifier(clientId, clientSecret);
72+
const client = await verifyFn(clientId, clientSecret);
6973
if (!client) {
7074
throw new HttpErrors.Unauthorized(AuthErrorKeys.ClientInvalid);
7175
} else if (

src/strategies/passport/passport-client-password/client-password-verify.provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class ClientPasswordVerifyProvider
1313
constructor() {}
1414

1515
value(): VerifyFunction.OauthClientPasswordFn {
16-
return async (clientId, clientSecret) => {
16+
return async (clientId: string, clientSecret: string) => {
1717
throw new HttpErrors.NotImplemented(
1818
`VerifyFunction.OauthClientPasswordFn is not implemented`,
1919
);

src/strategies/passport/passport-google-oauth2/google-auth-strategy-factory-provider.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import {Strategies} from '../../keys';
1414
import {VerifyFunction} from '../../types';
1515

1616
export interface GoogleAuthStrategyFactory {
17-
(options: StrategyOptions | StrategyOptionsWithRequest): Strategy;
17+
(
18+
options: StrategyOptions | StrategyOptionsWithRequest,
19+
verifierPassed?: VerifyFunction.GoogleAuthFn,
20+
): Strategy;
1821
}
1922

2023
export class GoogleAuthStrategyFactoryProvider
@@ -25,12 +28,15 @@ export class GoogleAuthStrategyFactoryProvider
2528
) {}
2629

2730
value(): GoogleAuthStrategyFactory {
28-
return (options) => this.getGoogleAuthStrategyVerifier(options);
31+
return (options, verifier) =>
32+
this.getGoogleAuthStrategyVerifier(options, verifier);
2933
}
3034

3135
getGoogleAuthStrategyVerifier(
3236
options: StrategyOptions | StrategyOptionsWithRequest,
37+
verifierPassed?: VerifyFunction.GoogleAuthFn,
3338
): Strategy {
39+
const verifyFn = verifierPassed ?? this.verifierGoogleAuth;
3440
if (options && options.passReqToCallback === true) {
3541
return new Strategy(
3642
options,
@@ -44,7 +50,7 @@ export class GoogleAuthStrategyFactoryProvider
4450
cb: VerifyCallback,
4551
) => {
4652
try {
47-
const user = await this.verifierGoogleAuth(
53+
const user = await verifyFn(
4854
accessToken,
4955
refreshToken,
5056
profile,
@@ -73,12 +79,7 @@ export class GoogleAuthStrategyFactoryProvider
7379
cb: VerifyCallback,
7480
) => {
7581
try {
76-
const user = await this.verifierGoogleAuth(
77-
accessToken,
78-
refreshToken,
79-
profile,
80-
cb,
81-
);
82+
const user = await verifyFn(accessToken, refreshToken, profile, cb);
8283
if (!user) {
8384
throw new HttpErrors.Unauthorized(
8485
AuthErrorKeys.InvalidCredentials,

src/strategies/passport/passport-keycloak/keycloak-strategy-factory-provider.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import {KeycloakProfile, VerifyFunction} from '../../types';
99
export const KeycloakStrategy = require('@exlinc/keycloak-passport');
1010

1111
export interface KeycloakStrategyFactory {
12-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
13-
(options: any): typeof KeycloakStrategy;
12+
(
13+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
14+
options: any,
15+
verifierPassed?: VerifyFunction.KeycloakAuthFn,
16+
): typeof KeycloakStrategy;
1417
}
1518

1619
export class KeycloakStrategyFactoryProvider
@@ -21,11 +24,16 @@ export class KeycloakStrategyFactoryProvider
2124
) {}
2225

2326
value(): KeycloakStrategyFactory {
24-
return (options) => this.getKeycloakAuthStrategyVerifier(options);
27+
return (options, verifier) =>
28+
this.getKeycloakAuthStrategyVerifier(options, verifier);
2529
}
2630

27-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
28-
getKeycloakAuthStrategyVerifier(options: any): typeof KeycloakStrategy {
31+
getKeycloakAuthStrategyVerifier(
32+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33+
options: any,
34+
verifierPassed?: VerifyFunction.KeycloakAuthFn,
35+
): typeof KeycloakStrategy {
36+
const verifyFn = verifierPassed ?? this.verifierKeycloak;
2937
return new KeycloakStrategy(
3038
options,
3139
async (
@@ -35,12 +43,7 @@ export class KeycloakStrategyFactoryProvider
3543
cb: (err?: string | Error, user?: IAuthUser) => void,
3644
) => {
3745
try {
38-
const user = await this.verifierKeycloak(
39-
accessToken,
40-
refreshToken,
41-
profile,
42-
cb,
43-
);
46+
const user = await verifyFn(accessToken, refreshToken, profile, cb);
4447
if (!user) {
4548
throw new HttpErrors.Unauthorized(AuthErrorKeys.InvalidCredentials);
4649
}

src/strategies/passport/passport-local/local-password-strategy-factory-provider.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export interface LocalPasswordStrategyFactory {
1313
options?:
1414
| PassportLocal.IStrategyOptions
1515
| PassportLocal.IStrategyOptionsWithRequest,
16+
verifierPassed?: VerifyFunction.LocalPasswordFn,
1617
): PassportLocal.Strategy;
1718
}
1819

@@ -24,14 +25,17 @@ export class LocalPasswordStrategyFactoryProvider
2425
) {}
2526

2627
value(): LocalPasswordStrategyFactory {
27-
return (options) => this.getLocalStrategyVerifier(options);
28+
return (options, verifier) =>
29+
this.getLocalStrategyVerifier(options, verifier);
2830
}
2931

3032
getLocalStrategyVerifier(
3133
options?:
3234
| PassportLocal.IStrategyOptions
3335
| PassportLocal.IStrategyOptionsWithRequest,
36+
verifierPassed?: VerifyFunction.LocalPasswordFn,
3437
): PassportLocal.Strategy {
38+
const verifyFn = verifierPassed ?? this.verifierLocal;
3539
if (options?.passReqToCallback) {
3640
return new PassportLocal.Strategy(
3741
options,
@@ -43,7 +47,7 @@ export class LocalPasswordStrategyFactoryProvider
4347
cb: (err: Error | null, user?: IAuthUser | false) => void,
4448
) => {
4549
try {
46-
const user = await this.verifierLocal(username, password, req);
50+
const user = await verifyFn(username, password, req);
4751
if (!user) {
4852
throw new HttpErrors.Unauthorized(
4953
AuthErrorKeys.InvalidCredentials,
@@ -65,7 +69,7 @@ export class LocalPasswordStrategyFactoryProvider
6569
cb: (err: Error | null, user?: IAuthUser | false) => void,
6670
) => {
6771
try {
68-
const user = await this.verifierLocal(username, password);
72+
const user = await verifyFn(username, password);
6973
if (!user) {
7074
throw new HttpErrors.Unauthorized(
7175
AuthErrorKeys.InvalidCredentials,
@@ -86,11 +90,7 @@ export class LocalPasswordStrategyFactoryProvider
8690
cb: (err: Error | null, user?: IAuthUser | false) => void,
8791
) => {
8892
try {
89-
const user = await this.verifierLocal(
90-
username,
91-
password,
92-
undefined,
93-
);
93+
const user = await verifyFn(username, password, undefined);
9494
if (!user) {
9595
throw new HttpErrors.Unauthorized(
9696
AuthErrorKeys.InvalidCredentials,

src/strategies/passport/passport-local/local-password-verify.provider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export class LocalPasswordVerifyProvider
1313
constructor() {}
1414

1515
value(): VerifyFunction.LocalPasswordFn {
16-
return async (username, password) => {
16+
return async (username: string, password: string) => {
1717
throw new HttpErrors.NotImplemented(
1818
`VerifyFunction.LocalPasswordFn is not implemented`,
1919
);

0 commit comments

Comments
 (0)