Skip to content

✨ feat(auth-microservice) [OTP]: email one-time-code login routes + passwordless provisioning for CGIAR center domains - #38

Merged
JuankCadavid merged 3 commits into
dev-authfrom
dev-auth-otp
Sep 12, 2026
Merged

JuankCadavid merged 3 commits into
dev-authfrom
dev-auth-otp

Conversation

@JuankCadavid

Copy link
Copy Markdown
Contributor

What

Third /login path for CGIAR center staff outside AD (@cifor-icraf.org, @icrisat.org): PRMS calls this microservice, which drives the Cognito passwordless USER_AUTH / EMAIL_OTP flow. Spec: docs/specs/changes/cognito-email-otp-login in the PRMS repo.

  • CognitoService.startEmailOtp / verifyEmailOtp — InitiateAuth (PREFERRED_CHALLENGE: EMAIL_OTP) and RespondToAuthChallenge, Cognito errors mapped to stable codes (CODE_MISMATCH, CODE_EXPIRED, ATTEMPTS_EXCEEDED, NOT_AUTHORIZED, CHALLENGE_NOT_SUPPORTED, UPSTREAM_ERROR).
  • POST /auth/login/otp/start { username } → { challengeName, session, codeDeliveryDestination }; POST /auth/login/otp/verify { username, code, session } → { tokens } (same shape as login/custom). Same auth header / JwtClarisaMiddleware as every /auth/* route.
  • Route-local OtpHttpExceptionFilter so the stable code survives the global filter on the wire.
  • LoggingInterceptor now redacts session / tokens / password-like keys before the response log line (log line only; client body untouched). This also closes the pre-existing token exposure on login/custom.
  • PASSWORDLESS_DOMAINS (new env): users registered with an email on a listed domain are created without a temporary password (MessageAction: SUPPRESS) so they land CONFIRMED, and the welcome email is skipped. Non-listed domains are byte-identical to today.

Review first

src/api/auth/cognito.service.ts (payloads + error mapping), then src/shared/interceptors/logging.interceptor.ts (redaction). Out of scope: any PRMS change (PR in the PRMS repo links here).

Deploy notes (TEST)

  • New env var: PASSWORDLESS_DOMAINS=cifor-icraf.org,icrisat.org.
  • No Cognito change required by this PR (the TEST pool already allows EMAIL_OTP; general-client unchanged).
  • Existing routes unchanged; both OTP routes return 201 like login/custom.

Verification

npx jest --silent → 17 suites / 365 tests; tsc --noEmit clean; eslint clean on touched files. Request-level suite (auth.otp-routes.spec.ts) runs through the real global filter, pipe and interceptor.

🤖 Generated with Claude Code

JuankCadavid and others added 3 commits September 11, 2026 14:35
… to CognitoService with stable error mapping

[SPEC:changes/cognito-email-otp-login] Cognito USER_AUTH + EMAIL_OTP: InitiateAuth (PREFERRED_CHALLENGE), gated SELECT_CHALLENGE round-trip, RespondToAuthChallenge EMAIL_OTP → tokens; pure mapCognitoError (CODE_MISMATCH, CODE_EXPIRED, ATTEMPTS_EXCEEDED, NOT_AUTHORIZED, CHALLENGE_NOT_SUPPORTED, UPSTREAM_ERROR); outcome-only logs. 22 tests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…users without a temporary password so they land CONFIRMED

[SPEC:changes/cognito-email-otp-login] createUser omits TemporaryPassword (SUPPRESS, email_verified) for allow-listed domains and skips the welcome-password email; all other domains byte-identical. README env row.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d auth/login/otp/verify routes with stable error codes on the wire

- EmailOtpStartDto / EmailOtpVerifyDto, thin AuthService delegates to CognitoService
- route-local OtpHttpExceptionFilter keeps { code, message } in error bodies
- LoggingInterceptor redacts session/tokens/code keys before the response log line (OTP-R-11)
- request-level supertest suite through the real global filter, pipe and interceptor
- README: endpoints, actual error body, 201, telemetry vocabulary

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
5.9% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@JuankCadavid
JuankCadavid merged commit 65758f4 into dev-auth Sep 12, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant