Browse Source

feat: enhance OIDC strategy and state store with improved error handling and type definitions

pull/5981/head
Germán Martín 2 weeks ago
parent
commit
5bc176df71
  1. 16
      apps/api/src/app/auth/auth.module.ts
  2. 10
      apps/api/src/app/auth/oidc-state.store.ts
  3. 50
      apps/api/src/app/auth/oidc.strategy.ts

16
apps/api/src/app/auth/auth.module.ts

@ -88,16 +88,30 @@ import { OidcStrategy } from './oidc.strategy';
options.userInfoURL = config.userinfo_endpoint;
} catch (error) {
Logger.error(error, 'OidcStrategy');
throw new Error('Failed to fetch OIDC configuration from issuer');
}
} else {
options.authorizationURL = configurationService.get(
'OIDC_AUTHORIZATION_URL'
);
options.issuer = configurationService.get('OIDC_ISSUER');
options.tokenURL = configurationService.get('OIDC_TOKEN_URL');
options.userInfoURL = configurationService.get('OIDC_USER_INFO_URL');
}
return new OidcStrategy(authService, options);
return new OidcStrategy(
authService,
options as {
authorizationURL: string;
callbackURL: string;
clientID: string;
clientSecret: string;
issuer: string;
scope: string[];
tokenURL: string;
userInfoURL: string;
}
);
},
inject: [AuthService, ConfigurationService]
},

10
apps/api/src/app/auth/oidc-state.store.ts

@ -6,8 +6,8 @@ export class OidcStateStore {
private stateMap = new Map<
string,
{
ctx: { maxAge?: number; nonce?: string; issued?: Date };
appState?: unknown;
ctx: { maxAge?: number; nonce?: string; issued?: Date };
meta?: unknown;
timestamp: number;
}
@ -18,9 +18,9 @@ export class OidcStateStore {
// Signature matches passport-openidconnect SessionStore
public store(
_req: unknown,
ctx: { maxAge?: number; nonce?: string; issued?: Date },
appState: unknown,
_meta: unknown,
appState: unknown,
ctx: { maxAge?: number; nonce?: string; issued?: Date },
callback: (err: Error | null, handle?: string) => void
): void {
try {
@ -50,8 +50,8 @@ export class OidcStateStore {
handle: string,
callback: (
err: Error | null,
ctx?: { maxAge?: number; nonce?: string; issued?: Date },
appState?: unknown
appState?: unknown,
ctx?: { maxAge?: number; nonce?: string; issued?: Date }
) => void
): void {
try {

50
apps/api/src/app/auth/oidc.strategy.ts

@ -8,14 +8,33 @@ import { AuthService } from './auth.service';
import { OidcStateStore } from './oidc-state.store';
interface OidcStrategyOptions {
authorizationURL?: string;
authorizationURL: string;
callbackURL: string;
clientID: string;
clientSecret: string;
issuer?: string;
issuer: string;
scope?: string[];
tokenURL?: string;
userInfoURL?: string;
tokenURL: string;
userInfoURL: string;
}
interface OidcProfile {
id?: string;
sub?: string;
}
interface OidcContext {
claims?: {
sub?: string;
};
}
interface OidcIdToken {
sub?: string;
}
interface OidcParams {
sub?: string;
}
@Injectable()
@ -30,25 +49,32 @@ export class OidcStrategy extends PassportStrategy(Strategy, 'oidc') {
...options,
passReqToCallback: true,
store: OidcStrategy.stateStore
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any);
});
}
public async validate(
_request: Request,
_issuer: string,
profile: { id?: string },
context: { claims?: { sub?: string } },
idToken: { sub?: string },
issuer: string,
profile: OidcProfile,
context: OidcContext,
idToken: OidcIdToken,
_accessToken: string,
_refreshToken: string,
params: { sub?: string }
params: OidcParams
) {
try {
const thirdPartyId =
params?.sub || idToken?.sub || context?.claims?.sub || profile?.id;
profile?.id ??
profile?.sub ??
idToken?.sub ??
params?.sub ??
context?.claims?.sub;
if (!thirdPartyId) {
Logger.error(
`Missing subject identifier in OIDC response from ${issuer}`,
'OidcStrategy'
);
throw new Error('Missing subject identifier in OIDC response');
}

Loading…
Cancel
Save