fix(auth): one-time SSO and MFA tokens, permission changes effective on every replica
- Every JWT carries a jti. The SSO completion token and the MFA challenge (once a code was accepted) are recorded as used in ConsumedToken; a replayed request or copied cookie cannot open a second session. Used ids are cleaned up after they expire. - The token-validity check (active user, active role, password change) reads fresh on every request and refreshes the permission cache, so a deactivation or role change made on another replica applies to the very next request instead of up to 30 s later. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
fc6af8737b
commit
45efb08369
16 files changed
+166
-23
No files matched your search
@@ -9,6 +9,7 @@ import {
|
||||
verifyTotpStep,
|
||||
} from './totp.util';
|
||||
import {
|
||||
OneTimeTokenClaims,
|
||||
TOKEN_AUDIENCE,
|
||||
jwtSignOptions,
|
||||
jwtVerifyOptions,
|
||||
@@ -91,13 +92,15 @@ export class MfaService {
|
||||
);
|
||||
}
|
||||
|
||||
verifyChallengeToken(challengeToken: string): { userId: string } {
|
||||
let payload: ChallengeTokenPayload;
|
||||
verifyChallengeToken(challengeToken: string): {
|
||||
userId: string;
|
||||
claims: OneTimeTokenClaims;
|
||||
} {
|
||||
let payload: ChallengeTokenPayload & OneTimeTokenClaims;
|
||||
try {
|
||||
payload = this.jwtService.verify<ChallengeTokenPayload>(
|
||||
challengeToken,
|
||||
jwtVerifyOptions(TOKEN_AUDIENCE.mfaChallenge),
|
||||
);
|
||||
payload = this.jwtService.verify<
|
||||
ChallengeTokenPayload & OneTimeTokenClaims
|
||||
>(challengeToken, jwtVerifyOptions(TOKEN_AUDIENCE.mfaChallenge));
|
||||
} catch {
|
||||
throw new UnauthorizedException(
|
||||
'Anmeldung abgelaufen, bitte erneut mit E-Mail und Passwort anmelden',
|
||||
@@ -106,7 +109,10 @@ export class MfaService {
|
||||
if (payload.purpose !== CHALLENGE_TOKEN_PURPOSE) {
|
||||
throw new UnauthorizedException('Ungültiger Token');
|
||||
}
|
||||
return { userId: payload.sub };
|
||||
return {
|
||||
userId: payload.sub,
|
||||
claims: { jti: payload.jti, exp: payload.exp },
|
||||
};
|
||||
}
|
||||
|
||||
/** See verifyTotpStep; use AccountGuardService.consumeTotp for logins. */
|
||||
|
||||
Reference in new issue
Block a user