1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 05:13:29 +00:00

feat(AuthRouteConstants): [Auth/PM-27370] Convert auth routes to use constants (#16980)

* PM-22663 WIP on auth route constants

* PM-22663 - Convert desktop & extension to use constants - first pass

* PM-22663 - Further clean up

* PM-22663 - catch more missed routes

* PM-22663 - add barrel files

* PM-22663 - Per PR feedback, add missing as const

* PM-22663 - Per PR feedback and TS docs, use same name for const enum like and derived type. Adjusted filenames to be singular.

* PM-22663 - Per PR feedback update desktop app routing module since auto rename didn't update it for whatever reason.
This commit is contained in:
Jared Snider
2025-10-29 19:28:21 -04:00
committed by GitHub
parent 51a557514f
commit a1570fc8b1
9 changed files with 131 additions and 59 deletions

View File

@@ -0,0 +1,8 @@
// Full routes that auth owns in the extension
export const AuthExtensionRoute = Object.freeze({
AccountSecurity: "account-security",
DeviceManagement: "device-management",
AccountSwitcher: "account-switcher",
} as const);
export type AuthExtensionRoute = (typeof AuthExtensionRoute)[keyof typeof AuthExtensionRoute];

View File

@@ -0,0 +1 @@
export * from "./auth-extension-route.constant";

View File

@@ -2,6 +2,7 @@ import { Injectable, NgModule } from "@angular/core";
import { ActivatedRouteSnapshot, RouteReuseStrategy, RouterModule, Routes } from "@angular/router";
import { AuthenticationTimeoutComponent } from "@bitwarden/angular/auth/components/authentication-timeout.component";
import { AuthRoute } from "@bitwarden/angular/auth/constants";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/environment-selector/environment-selector.component";
import {
activeAuthGuard,
@@ -45,6 +46,7 @@ import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/co
import { LockComponent, ConfirmKeyConnectorDomainComponent } from "@bitwarden/key-management-ui";
import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component";
import { AuthExtensionRoute } from "../auth/popup/constants/auth-extension-route.constant";
import { fido2AuthGuard } from "../auth/popup/guards/fido2-auth.guard";
import { AccountSecurityComponent } from "../auth/popup/settings/account-security.component";
import { ExtensionDeviceManagementComponent } from "../auth/popup/settings/extension-device-management.component";
@@ -148,7 +150,7 @@ const routes: Routes = [
component: ExtensionAnonLayoutWrapperComponent,
children: [
{
path: "authentication-timeout",
path: AuthRoute.AuthenticationTimeout,
canActivate: [unauthGuardFn(unauthRouteOverrides)],
children: [
{
@@ -167,7 +169,7 @@ const routes: Routes = [
],
},
{
path: "device-verification",
path: AuthRoute.NewDeviceVerification,
component: ExtensionAnonLayoutWrapperComponent,
canActivate: [unauthGuardFn(), activeAuthGuard()],
children: [{ path: "", component: NewDeviceVerificationComponent }],
@@ -259,13 +261,13 @@ const routes: Routes = [
data: { elevation: 1 } satisfies RouteDataProperties,
},
{
path: "account-security",
path: AuthExtensionRoute.AccountSecurity,
component: AccountSecurityComponent,
canActivate: [authGuard],
data: { elevation: 1 } satisfies RouteDataProperties,
},
{
path: "device-management",
path: AuthExtensionRoute.DeviceManagement,
component: ExtensionDeviceManagementComponent,
canActivate: [authGuard],
data: { elevation: 1 } satisfies RouteDataProperties,
@@ -341,7 +343,7 @@ const routes: Routes = [
component: ExtensionAnonLayoutWrapperComponent,
children: [
{
path: "signup",
path: AuthRoute.SignUp,
canActivate: [unauthGuardFn()],
data: {
elevation: 1,
@@ -361,13 +363,13 @@ const routes: Routes = [
component: RegistrationStartSecondaryComponent,
outlet: "secondary",
data: {
loginRoute: "/login",
loginRoute: `/${AuthRoute.Login}`,
} satisfies RegistrationStartSecondaryComponentData,
},
],
},
{
path: "finish-signup",
path: AuthRoute.FinishSignUp,
canActivate: [unauthGuardFn()],
data: {
pageIcon: LockIcon,
@@ -382,7 +384,7 @@ const routes: Routes = [
],
},
{
path: "set-initial-password",
path: AuthRoute.SetInitialPassword,
canActivate: [authGuard],
component: SetInitialPasswordComponent,
data: {
@@ -390,7 +392,7 @@ const routes: Routes = [
} satisfies RouteDataProperties,
},
{
path: "login",
path: AuthRoute.Login,
canActivate: [unauthGuardFn(unauthRouteOverrides), IntroCarouselGuard],
data: {
pageIcon: VaultIcon,
@@ -411,7 +413,7 @@ const routes: Routes = [
],
},
{
path: "login-with-passkey",
path: AuthRoute.LoginWithPasskey,
canActivate: [unauthGuardFn(unauthRouteOverrides)],
data: {
pageIcon: TwoFactorAuthSecurityKeyIcon,
@@ -434,7 +436,7 @@ const routes: Routes = [
],
},
{
path: "sso",
path: AuthRoute.Sso,
canActivate: [unauthGuardFn(unauthRouteOverrides)],
data: {
pageIcon: VaultIcon,
@@ -456,7 +458,7 @@ const routes: Routes = [
],
},
{
path: "login-with-device",
path: AuthRoute.LoginWithDevice,
canActivate: [redirectToVaultIfUnlockedGuard()],
data: {
pageIcon: DevicesIcon,
@@ -479,7 +481,7 @@ const routes: Routes = [
],
},
{
path: "hint",
path: AuthRoute.PasswordHint,
canActivate: [unauthGuardFn(unauthRouteOverrides)],
data: {
pageTitle: {
@@ -502,7 +504,7 @@ const routes: Routes = [
],
},
{
path: "admin-approval-requested",
path: AuthRoute.AdminApprovalRequested,
canActivate: [redirectToVaultIfUnlockedGuard()],
data: {
pageIcon: DevicesIcon,
@@ -519,7 +521,7 @@ const routes: Routes = [
children: [{ path: "", component: LoginViaAuthRequestComponent }],
},
{
path: "login-initiated",
path: AuthRoute.LoginInitiated,
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageIcon: DevicesIcon,
@@ -557,7 +559,7 @@ const routes: Routes = [
],
},
{
path: "2fa",
path: AuthRoute.TwoFactor,
canActivate: [unauthGuardFn(unauthRouteOverrides), TwoFactorAuthGuard],
children: [
{
@@ -576,7 +578,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & ExtensionAnonLayoutWrapperData,
},
{
path: "change-password",
path: AuthRoute.ChangePassword,
data: {
elevation: 1,
hideFooter: true,
@@ -698,7 +700,7 @@ const routes: Routes = [
canActivate: [authGuard, canAccessAtRiskPasswords, hasAtRiskPasswords],
},
{
path: "account-switcher",
path: AuthExtensionRoute.AccountSwitcher,
component: AccountSwitcherComponent,
data: { elevation: 4, doNotSaveUrl: true } satisfies RouteDataProperties,
},

View File

@@ -2,6 +2,7 @@ import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { AuthenticationTimeoutComponent } from "@bitwarden/angular/auth/components/authentication-timeout.component";
import { AuthRoute } from "@bitwarden/angular/auth/constants";
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/environment-selector/environment-selector.component";
import {
authGuard,
@@ -65,7 +66,7 @@ const routes: Routes = [
canActivate: [redirectGuard({ loggedIn: "/vault", loggedOut: "/login", locked: "/lock" })],
},
{
path: "authentication-timeout",
path: AuthRoute.AuthenticationTimeout,
component: AnonLayoutWrapperComponent,
children: [
{
@@ -81,7 +82,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
path: "device-verification",
path: AuthRoute.NewDeviceVerification,
component: AnonLayoutWrapperComponent,
canActivate: [unauthGuardFn(), activeAuthGuard()],
children: [{ path: "", component: NewDeviceVerificationComponent }],
@@ -123,7 +124,7 @@ const routes: Routes = [
component: AnonLayoutWrapperComponent,
children: [
{
path: "signup",
path: AuthRoute.SignUp,
canActivate: [unauthGuardFn()],
data: {
pageIcon: RegistrationUserAddIcon,
@@ -141,13 +142,13 @@ const routes: Routes = [
component: RegistrationStartSecondaryComponent,
outlet: "secondary",
data: {
loginRoute: "/login",
loginRoute: `/${AuthRoute.Login}`,
} satisfies RegistrationStartSecondaryComponentData,
},
],
},
{
path: "finish-signup",
path: AuthRoute.FinishSignUp,
canActivate: [unauthGuardFn()],
data: {
pageIcon: LockIcon,
@@ -160,7 +161,7 @@ const routes: Routes = [
],
},
{
path: "login",
path: AuthRoute.Login,
canActivate: [maxAccountsGuardFn()],
data: {
pageTitle: {
@@ -179,7 +180,7 @@ const routes: Routes = [
],
},
{
path: "login-initiated",
path: AuthRoute.LoginInitiated,
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageIcon: DevicesIcon,
@@ -187,7 +188,7 @@ const routes: Routes = [
children: [{ path: "", component: LoginDecryptionOptionsComponent }],
},
{
path: "sso",
path: AuthRoute.Sso,
data: {
pageIcon: VaultIcon,
pageTitle: {
@@ -207,7 +208,7 @@ const routes: Routes = [
],
},
{
path: "login-with-device",
path: AuthRoute.LoginWithDevice,
data: {
pageIcon: DevicesIcon,
pageTitle: {
@@ -227,7 +228,7 @@ const routes: Routes = [
],
},
{
path: "admin-approval-requested",
path: AuthRoute.AdminApprovalRequested,
data: {
pageIcon: DevicesIcon,
pageTitle: {
@@ -240,7 +241,7 @@ const routes: Routes = [
children: [{ path: "", component: LoginViaAuthRequestComponent }],
},
{
path: "hint",
path: AuthRoute.PasswordHint,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -278,7 +279,7 @@ const routes: Routes = [
],
},
{
path: "2fa",
path: AuthRoute.TwoFactor,
canActivate: [unauthGuardFn(), TwoFactorAuthGuard],
children: [
{
@@ -295,7 +296,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
path: "set-initial-password",
path: AuthRoute.SetInitialPassword,
canActivate: [authGuard],
component: SetInitialPasswordComponent,
data: {
@@ -304,7 +305,7 @@ const routes: Routes = [
} satisfies AnonLayoutWrapperData,
},
{
path: "change-password",
path: AuthRoute.ChangePassword,
component: ChangePasswordComponent,
canActivate: [authGuard],
data: {

View File

@@ -0,0 +1,35 @@
// Web route segments auth owns under shared infrastructure
export const AuthWebRouteSegment = Object.freeze({
// settings routes
Account: "account",
EmergencyAccess: "emergency-access",
// settings/security routes
Password: "password",
TwoFactor: "two-factor",
SecurityKeys: "security-keys",
DeviceManagement: "device-management",
} as const);
export type AuthWebRouteSegment = (typeof AuthWebRouteSegment)[keyof typeof AuthWebRouteSegment];
// Full routes that auth owns in the web app
export const AuthWebRoute = Object.freeze({
SignUpLinkExpired: "signup-link-expired",
RecoverTwoFactor: "recover-2fa",
AcceptEmergencyAccessInvite: "accept-emergency",
RecoverDeleteAccount: "recover-delete",
VerifyRecoverDeleteAccount: "verify-recover-delete",
AcceptOrganizationInvite: "accept-organization",
// Composed routes from segments (allowing for router.navigate / routerLink usage)
AccountSettings: `settings/${AuthWebRouteSegment.Account}`,
EmergencyAccessSettings: `settings/${AuthWebRouteSegment.EmergencyAccess}`,
PasswordSettings: `settings/security/${AuthWebRouteSegment.Password}`,
TwoFactorSettings: `settings/security/${AuthWebRouteSegment.TwoFactor}`,
SecurityKeysSettings: `settings/security/${AuthWebRouteSegment.SecurityKeys}`,
DeviceManagement: `settings/security/${AuthWebRouteSegment.DeviceManagement}`,
} as const);
export type AuthWebRoute = (typeof AuthWebRoute)[keyof typeof AuthWebRoute];

View File

@@ -0,0 +1 @@
export * from "./auth-web-route.constant";

View File

@@ -2,6 +2,7 @@ import { NgModule } from "@angular/core";
import { Route, RouterModule, Routes } from "@angular/router";
import { AuthenticationTimeoutComponent } from "@bitwarden/angular/auth/components/authentication-timeout.component";
import { AuthRoute } from "@bitwarden/angular/auth/constants";
import {
authGuard,
lockGuard,
@@ -55,6 +56,7 @@ import { VerifyRecoverDeleteOrgComponent } from "./admin-console/organizations/m
import { AcceptFamilySponsorshipComponent } from "./admin-console/organizations/sponsorships/accept-family-sponsorship.component";
import { FamiliesForEnterpriseSetupComponent } from "./admin-console/organizations/sponsorships/families-for-enterprise-setup.component";
import { CreateOrganizationComponent } from "./admin-console/settings/create-organization.component";
import { AuthWebRoute, AuthWebRouteSegment } from "./auth/constants/auth-web-route.constant";
import { deepLinkGuard } from "./auth/guards/deep-link/deep-link.guard";
import { AcceptOrganizationComponent } from "./auth/organization-invite/accept-organization.component";
import { RecoverDeleteComponent } from "./auth/recover-delete.component";
@@ -93,12 +95,12 @@ const routes: Routes = [
// so that the redirectGuard does not interrupt the navigation.
{
path: "register",
redirectTo: "signup",
redirectTo: AuthRoute.SignUp,
pathMatch: "full",
},
{
path: "trial",
redirectTo: "signup",
redirectTo: AuthRoute.SignUp,
pathMatch: "full",
},
{
@@ -114,7 +116,7 @@ const routes: Routes = [
},
{ path: "verify-email", component: VerifyEmailTokenComponent },
{
path: "accept-organization",
path: AuthWebRoute.AcceptOrganizationInvite,
canActivate: [deepLinkGuard()],
component: AcceptOrganizationComponent,
data: { titleId: "joinOrganization", doNotSaveUrl: false } satisfies RouteDataProperties,
@@ -128,7 +130,7 @@ const routes: Routes = [
doNotSaveUrl: false,
} satisfies RouteDataProperties,
},
{ path: "recover", pathMatch: "full", redirectTo: "recover-2fa" },
{ path: "recover", pathMatch: "full", redirectTo: AuthWebRoute.RecoverTwoFactor },
{
path: "verify-recover-delete-org",
component: VerifyRecoverDeleteOrgComponent,
@@ -142,7 +144,7 @@ const routes: Routes = [
component: AnonLayoutWrapperComponent,
children: [
{
path: "login-with-passkey",
path: AuthRoute.LoginWithPasskey,
canActivate: [unauthGuardFn()],
data: {
pageIcon: TwoFactorAuthSecurityKeyIcon,
@@ -164,7 +166,7 @@ const routes: Routes = [
],
},
{
path: "signup",
path: AuthRoute.SignUp,
canActivate: [unauthGuardFn()],
data: {
pageIcon: RegistrationUserAddIcon,
@@ -189,7 +191,7 @@ const routes: Routes = [
],
},
{
path: "finish-signup",
path: AuthRoute.FinishSignUp,
canActivate: [unauthGuardFn()],
data: {
pageIcon: LockIcon,
@@ -203,7 +205,7 @@ const routes: Routes = [
],
},
{
path: "login",
path: AuthRoute.Login,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -229,7 +231,7 @@ const routes: Routes = [
],
},
{
path: "login-with-device",
path: AuthRoute.LoginWithDevice,
data: {
pageIcon: DevicesIcon,
pageTitle: {
@@ -250,7 +252,7 @@ const routes: Routes = [
],
},
{
path: "admin-approval-requested",
path: AuthRoute.AdminApprovalRequested,
data: {
pageIcon: DevicesIcon,
pageTitle: {
@@ -264,7 +266,7 @@ const routes: Routes = [
children: [{ path: "", component: LoginViaAuthRequestComponent }],
},
{
path: "hint",
path: AuthRoute.PasswordHint,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -286,7 +288,7 @@ const routes: Routes = [
],
},
{
path: "login-initiated",
path: AuthRoute.LoginInitiated,
canActivate: [tdeDecryptionRequiredGuard()],
data: {
pageIcon: DevicesIcon,
@@ -315,7 +317,7 @@ const routes: Routes = [
],
},
{
path: "set-initial-password",
path: AuthRoute.SetInitialPassword,
canActivate: [authGuard],
component: SetInitialPasswordComponent,
data: {
@@ -324,7 +326,7 @@ const routes: Routes = [
} satisfies AnonLayoutWrapperData,
},
{
path: "signup-link-expired",
path: AuthWebRoute.SignUpLinkExpired,
canActivate: [unauthGuardFn()],
data: {
pageIcon: TwoFactorTimeoutIcon,
@@ -337,13 +339,13 @@ const routes: Routes = [
path: "",
component: RegistrationLinkExpiredComponent,
data: {
loginRoute: "/login",
loginRoute: `/${AuthRoute.Login}`,
} satisfies RegistrationStartSecondaryComponentData,
},
],
},
{
path: "sso",
path: AuthRoute.Sso,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -368,7 +370,7 @@ const routes: Routes = [
],
},
{
path: "2fa",
path: AuthRoute.TwoFactor,
component: TwoFactorAuthComponent,
canActivate: [unauthGuardFn(), TwoFactorAuthGuard],
children: [
@@ -408,7 +410,7 @@ const routes: Routes = [
} satisfies AnonLayoutWrapperData,
},
{
path: "authentication-timeout",
path: AuthRoute.AuthenticationTimeout,
canActivate: [unauthGuardFn()],
children: [
{
@@ -430,7 +432,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
path: "recover-2fa",
path: AuthWebRoute.RecoverTwoFactor,
canActivate: [unauthGuardFn()],
children: [
{
@@ -452,7 +454,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
path: "device-verification",
path: AuthRoute.NewDeviceVerification,
canActivate: [unauthGuardFn(), activeAuthGuard()],
children: [
{
@@ -471,7 +473,7 @@ const routes: Routes = [
} satisfies RouteDataProperties & AnonLayoutWrapperData,
},
{
path: "accept-emergency",
path: AuthWebRoute.AcceptEmergencyAccessInvite,
canActivate: [deepLinkGuard()],
data: {
pageTitle: {
@@ -492,7 +494,7 @@ const routes: Routes = [
],
},
{
path: "recover-delete",
path: AuthWebRoute.RecoverDeleteAccount,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -514,7 +516,7 @@ const routes: Routes = [
],
},
{
path: "verify-recover-delete",
path: AuthWebRoute.VerifyRecoverDeleteAccount,
canActivate: [unauthGuardFn()],
data: {
pageTitle: {
@@ -596,7 +598,7 @@ const routes: Routes = [
],
},
{
path: "change-password",
path: AuthRoute.ChangePassword,
component: ChangePasswordComponent,
canActivate: [authGuard],
data: {
@@ -652,9 +654,9 @@ const routes: Routes = [
{
path: "settings",
children: [
{ path: "", pathMatch: "full", redirectTo: "account" },
{ path: "", pathMatch: "full", redirectTo: AuthWebRouteSegment.Account },
{
path: "account",
path: AuthWebRouteSegment.Account,
component: AccountComponent,
data: { titleId: "myAccount" } satisfies RouteDataProperties,
},
@@ -680,7 +682,7 @@ const routes: Routes = [
),
},
{
path: "emergency-access",
path: AuthWebRouteSegment.EmergencyAccess,
children: [
{
path: "",

View File

@@ -0,0 +1,21 @@
/**
* Constants for auth team owned full routes which are shared across clients.
*/
export const AuthRoute = Object.freeze({
SignUp: "signup",
FinishSignUp: "finish-signup",
Login: "login",
LoginWithDevice: "login-with-device",
AdminApprovalRequested: "admin-approval-requested",
PasswordHint: "hint",
LoginInitiated: "login-initiated",
SetInitialPassword: "set-initial-password",
ChangePassword: "change-password",
Sso: "sso",
TwoFactor: "2fa",
AuthenticationTimeout: "authentication-timeout",
NewDeviceVerification: "device-verification",
LoginWithPasskey: "login-with-passkey",
} as const);
export type AuthRoute = (typeof AuthRoute)[keyof typeof AuthRoute];

View File

@@ -0,0 +1 @@
export * from "./auth-route.constant";