mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
Merge branch 'alpha' into passenger/feat/iam
This commit is contained in:
@@ -23,7 +23,10 @@ export interface FaydaConfig {
|
||||
authorizationEndpoint: string;
|
||||
tokenEndpoint: string;
|
||||
userInfoEndpoint: string;
|
||||
/** OAuth redirect_uri sent to eSignet for MOBILE clients. */
|
||||
redirectUri: string;
|
||||
/** OAuth redirect_uri sent to eSignet for WEB clients. Falls back to `redirectUri`. */
|
||||
webRedirectUri: string;
|
||||
privateJwk: FaydaJwk;
|
||||
scope: string;
|
||||
acrValues: string;
|
||||
@@ -73,6 +76,7 @@ export default registerAs('fayda', (): FaydaConfig => {
|
||||
const claimsLocales = process.env.FAYDA_CLAIMS_LOCALES ?? 'en am';
|
||||
const sessionTtl = Number.parseInt(process.env.FAYDA_SESSION_TTL_MINUTES ?? '10', 10);
|
||||
const redirectUri = process.env.FAYDA_REDIRECT_URI ?? '';
|
||||
const webRedirectUri = process.env.FAYDA_WEB_REDIRECT_URI || redirectUri;
|
||||
if (!enabled) {
|
||||
return {
|
||||
enabled: false,
|
||||
@@ -81,6 +85,7 @@ export default registerAs('fayda', (): FaydaConfig => {
|
||||
tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT ?? '',
|
||||
userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT ?? '',
|
||||
redirectUri,
|
||||
webRedirectUri,
|
||||
privateJwk: { kty: 'RSA', n: '', e: '', d: '' },
|
||||
scope,
|
||||
acrValues,
|
||||
@@ -111,6 +116,7 @@ export default registerAs('fayda', (): FaydaConfig => {
|
||||
tokenEndpoint: process.env.FAYDA_TOKEN_ENDPOINT!,
|
||||
userInfoEndpoint: process.env.FAYDA_USERINFO_ENDPOINT!,
|
||||
redirectUri,
|
||||
webRedirectUri,
|
||||
privateJwk: decodePrivateJwk(process.env.FAYDA_PRIVATE_KEY_BASE64!),
|
||||
scope,
|
||||
acrValues,
|
||||
|
||||
@@ -16,7 +16,7 @@ export class StartVerificationDto {
|
||||
enum: ['WEB', 'MOBILE'],
|
||||
default: 'WEB',
|
||||
description:
|
||||
'Client platform. Decides where /callback redirects on completion: a web https URL (WEB) or a custom-scheme deep link the Flutter app intercepts (MOBILE).',
|
||||
'Client platform. Selects which OAuth redirect_uri is sent to eSignet: WEB uses FAYDA_WEB_REDIRECT_URI, MOBILE uses FAYDA_REDIRECT_URI. Both land on the same /complete endpoint with identical handling.',
|
||||
})
|
||||
@IsOptional()
|
||||
@IsIn(['WEB', 'MOBILE'])
|
||||
|
||||
@@ -35,6 +35,7 @@ function buildConfig(overrides?: Partial<FaydaConfig>): FaydaConfig {
|
||||
tokenEndpoint: 'https://esignet.test/token',
|
||||
userInfoEndpoint: 'https://esignet.test/userinfo',
|
||||
redirectUri: 'http://localhost:4000/fayda/verification/complete',
|
||||
webRedirectUri: 'http://localhost:5174/fayda/verification/complete',
|
||||
privateJwk: { kty: 'RSA', n: '', e: '', d: '' },
|
||||
scope: 'openid profile email',
|
||||
acrValues: 'mosip:idp:acr:generated-code',
|
||||
@@ -101,13 +102,14 @@ describe('VerifaydaService (OIDC, client-callback)', () => {
|
||||
expect(parsed.origin + parsed.pathname).toBe('https://esignet.test/authorize');
|
||||
expect(parsed.searchParams.get('client_id')).toBe('edr-test-client');
|
||||
expect(parsed.searchParams.get('code_challenge_method')).toBe('S256');
|
||||
// Default platform is WEB → webRedirectUri.
|
||||
expect(parsed.searchParams.get('redirect_uri')).toBe(
|
||||
'http://localhost:4000/fayda/verification/complete',
|
||||
'http://localhost:5174/fayda/verification/complete',
|
||||
);
|
||||
expect(parsed.searchParams.get('state')).toBe(created.state);
|
||||
});
|
||||
|
||||
it('uses the same single redirect_uri regardless of platform (platform is only recorded)', async () => {
|
||||
it('sends the MOBILE redirect_uri (base redirectUri) for MOBILE sessions', async () => {
|
||||
prisma.faydaVerificationSession.create.mockResolvedValue({});
|
||||
|
||||
const url = await service.startVerification({
|
||||
@@ -122,6 +124,19 @@ describe('VerifaydaService (OIDC, client-callback)', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('sends the WEB redirect_uri (webRedirectUri) for WEB sessions', async () => {
|
||||
prisma.faydaVerificationSession.create.mockResolvedValue({});
|
||||
|
||||
const url = await service.startVerification({
|
||||
purpose: 'VERIFY',
|
||||
platform: 'WEB',
|
||||
});
|
||||
|
||||
expect(new URL(url).searchParams.get('redirect_uri')).toBe(
|
||||
'http://localhost:5174/fayda/verification/complete',
|
||||
);
|
||||
});
|
||||
|
||||
it('throws ServiceUnavailable when fayda integration is disabled', async () => {
|
||||
const disabledService = new VerifaydaService(
|
||||
buildConfigService(buildConfig({ enabled: false })),
|
||||
|
||||
@@ -161,7 +161,18 @@ export class VerifaydaService {
|
||||
`Fayda verification started: purpose=${input.purpose} platform=${input.platform ?? 'WEB'} userId=${input.userId ?? 'none'}`,
|
||||
);
|
||||
|
||||
return this.buildAuthorizationUrl({ state, codeChallenge });
|
||||
return this.buildAuthorizationUrl({
|
||||
state,
|
||||
codeChallenge,
|
||||
redirectUri: this.redirectUriForPlatform(input.platform ?? 'WEB'),
|
||||
});
|
||||
}
|
||||
|
||||
/** WEB clients use `webRedirectUri`; MOBILE uses the base `redirectUri`. */
|
||||
private redirectUriForPlatform(platform?: FaydaPlatform): string {
|
||||
return platform === 'MOBILE'
|
||||
? this.faydaConfig.redirectUri
|
||||
: this.faydaConfig.webRedirectUri;
|
||||
}
|
||||
|
||||
|
||||
@@ -213,6 +224,7 @@ export class VerifaydaService {
|
||||
const tokens = await this.exchangeCodeForTokens(
|
||||
query.code,
|
||||
session.codeVerifier,
|
||||
this.redirectUriForPlatform(session.platform as FaydaPlatform),
|
||||
);
|
||||
const userInfo = await this.fetchUserInfo(tokens.access_token);
|
||||
const normalized = this.normalizeUserInfo(userInfo);
|
||||
@@ -307,11 +319,12 @@ export class VerifaydaService {
|
||||
private buildAuthorizationUrl(args: {
|
||||
state: string;
|
||||
codeChallenge: string;
|
||||
redirectUri: string;
|
||||
}): string {
|
||||
const params = new URLSearchParams({
|
||||
client_id: this.faydaConfig.clientId,
|
||||
response_type: 'code',
|
||||
redirect_uri: this.faydaConfig.redirectUri,
|
||||
redirect_uri: args.redirectUri,
|
||||
scope: this.faydaConfig.scope,
|
||||
state: args.state,
|
||||
code_challenge: args.codeChallenge,
|
||||
@@ -344,6 +357,7 @@ export class VerifaydaService {
|
||||
private async exchangeCodeForTokens(
|
||||
code: string,
|
||||
codeVerifier: string,
|
||||
redirectUri: string,
|
||||
): Promise<FaydaTokenResponse> {
|
||||
const clientAssertion = await generateClientAssertion({
|
||||
clientId: this.faydaConfig.clientId,
|
||||
@@ -354,7 +368,7 @@ export class VerifaydaService {
|
||||
const body = new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
redirect_uri: this.faydaConfig.redirectUri,
|
||||
redirect_uri: redirectUri,
|
||||
client_id: this.faydaConfig.clientId,
|
||||
client_assertion_type:
|
||||
'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
||||
|
||||
Reference in New Issue
Block a user