Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement One-Time Password logins and comprehensive token-based authentication #562

Merged
merged 77 commits into from
Aug 27, 2024

Conversation

tjementum
Copy link
Member

Summary & Motivation

Introduce a comprehensive token-based authentication system to handle One-Time Password (OTP) logins, as well as the issuing and validation of Refresh and Access Tokens (RT/AT). The Account Management self-contained system is responsible for generating the tokens, while the AppGateway intercepts all API calls, fetches the tokens from cookies, and manages the authentication flow.

If the Access Token is valid, the AppGateway forwards it as a Bearer token to the respective self-contained system API running behind the reverse proxy gateway. If the Access Token has expired, the AppGateway uses the Refresh Token to call a refresh endpoint in the Account Management system, obtaining a new Access Token before proceeding. This ensures a seamless and secure authentication experience.

To support this setup, a 64-bit signing key is generated by the Aspire AppHost on localhost and stored in .NET user secrets, enabling all self-contained systems to validate Access Tokens. In production, a 2048-bit RSA key is generated by Bicep and stored in KeyVault. Depending on the environment, either the DevelopmentTokenSigningService or the AzureTokenSigningService is used to sign and validate tokens.

The Access Token is valid for 5 minutes and is stored in a session cookie with strict security settings, while the Refresh Token, valid for 3 months, is stored in a separate cookie. The Access Token contains essential user information, such as name, title, avatar URL, and TenantID, which is also injected as an HTML meta tag for frontend use.

The Refresh Token is designed to minimize security risks, using several key elements:

  • JTI (JSON Web Token ID): A unique identifier that changes with each token issuance, ensuring that each token is distinct.
  • RefreshTokenID: An identifier used to track the specific Refresh Token, helping detect potential replay attacks.
  • RefreshVersion: This version is incremented each time a Refresh Token is used to issue a new Access Token, further enhancing the ability to detect and prevent replay attacks. The system is prepared to log and handle cases where a token’s version does not match the expected version, which could indicate an attempt to reuse an old token.

Additional Changes:

  • The existing Account Registration flow and endpoints have been renamed to Signup, with the /signup endpoint replacing /register.
  • The Single Page Application (SPA) has been updated to handle login and logout flows, including implementing the existing OTP login screen to generate an OTP, ensuring it cannot be brute-forced. This logic mirrors the existing Signup flow.
  • All API endpoints now require authentication by default, with AllowAnonymous explicitly set on endpoints that do not require authentication.
  • Tests have been updated to support authenticated calls.
  • The Shared WebApp has been updated with centralized logic for login and signup paths. The AuthenticationProvider has been simplified to support this streamlined approach.
  • The Avatar Menu has been enhanced to display user initials even when only the first name or last name is provided. Additionally, when the Update User Profile dialog is saved, the Access Token is refreshed to ensure the UI reflects the latest user information.
  • Bicep scripts have been added to create KeyVault RSA keys, including granting all self-contained systems read access to these keys. Issuer and Audience secrets have also been centralized in KeyVault, although they are not truly secrets.

Checklist

  • I have added a Label to the pull-request
  • I have added tests, and done manual regression tests
  • I have updated the documentation, if necessary

@tjementum tjementum added the Enhancement New feature or request label Aug 27, 2024
@tjementum tjementum self-assigned this Aug 27, 2024
@tjementum tjementum requested a review from a team as a code owner August 27, 2024 16:58
@tjementum tjementum linked an issue Aug 27, 2024 that may be closed by this pull request
tjementum and others added 23 commits August 27, 2024 19:43
…mand, and delete dummy authentication/{email} endpoint

# Conflicts:
#	application/account-management/Api/Authentication/AuthenticationEndpoints.cs
…s, namespaces, domain and database artifacts, etc.
… a line break at the end of the JSON response
…es instead, eliminating the need for the Data Protection API
…rameters and extract shared logic for Refresh and Access token generation
…ey for signing authentication tokens, and use this in `DevelopmentTokenSigningService`
@tjementum tjementum force-pushed the 315-one-time-password-sign-in branch from 7f57426 to 5e04fb2 Compare August 27, 2024 17:46
Copy link

Quality Gate Failed Quality Gate failed

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

See analysis details on SonarCloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request
Projects
None yet
2 participants