Authentication
The authentication subsystem lives entirely in src/app/core/auth/ and is
registered by AuthModule.forRoot().
Login pipeline
LoginComponent submits { email, password }
→ reCAPTCHA v3 executes and yields a token
→ AuthService.login(email, password, recaptchaToken)
GET {authUrl}/token?timezon=<IANA tz>
headers: Authorization: Basic base64(email:password)
recaptcha: <token>
← { token }
→ dispatch login({ authToken })
→ AuthEffects.login$ : localStorage[authTokenKey] = authToken
→ userRequested()
→ AuthEffects.loadUser$ : AuthService.getUserByToken()
GET supplier details (SupplierDto)
GET supplier status (SupplierStatusDto)
→ EventLoggerService.identify(user)
→ userLoaded({ user })
→ userPermissionsRequested()
→ userDashboardStatusRequested({ user })
→ loadBalance()
→ AuthEffects.loadedUserPermissions$
: PermissionsService.getUserPermissions(user)
→ userPermissionsLoaded({ permissions })
→ GlobalSubscriptionsService mirrors permissions into NgxPermissionsService
→ Router activates the requested route
|
The |
Session restoration
AuthEffects.init$ runs once at startup:
init$ = createEffect(() =>
defer(() => {
const authToken = localStorage.getItem(this.env.authTokenKey);
return authToken ? of(AuthActions.login({ authToken })) : of(noAction());
}),
);
A stored token re-enters the same pipeline as a fresh login, so user data and permissions are always recomputed rather than trusted from persisted state.
Logout
logout$ = createEffect(() =>
this.actions$.pipe(
ofType(AuthActions.logout),
tap(() => {
this.stateManager.clear(); (1)
localStorage.removeItem(this.env.authTokenKey); (2)
setTimeout(() => location.reload(), 1000); (3)
}),
),
{ dispatch: false },
);
| 1 | PersistentStateManager.clear() wipes persisted slices. |
| 2 | The session token is removed. |
| 3 | A full page reload after 1 s guarantees no in-memory state survives — cheaper and safer than resetting every slice by hand. |
AuthService
src/app/core/auth/_services/auth.service.ts
Session
| Method | Behaviour |
|---|---|
|
|
|
|
|
|
|
Write / delete the token. |
|
The header set applied to every authenticated request — see HTTP Interceptors. |
User loading and mapping
| Method | Behaviour |
|---|---|
|
|
|
Maps |
|
DTO → model mappers for the sub-objects. |
|
|
Registration and password reset
| Method | Endpoint |
|---|---|
|
|
|
|
|
|
|
|
|
|
Password reset flow
1. /auth/reset-password → requestPassword(email, recaptcha)
POST /start_password_reset
2. Supplier receives an email with a link carrying ?r=<verificationCode>
3. /auth/new-password?r=… → NewPasswordTokenGuard
POST /confirm_password_reset/<code>
invalid → warning banner + redirect to /auth/login
4. NewPasswordComponent submits → dispatch newPasswordRequest({ password, verificationCode })
5. AuthEffects.newUserPasswordRequest$
confirmPasswordReset(code) → { token }
executePasswordChange(password, token)
→ newPasswordRequestSuccess | newPasswordRequestError
Impersonation — login as supplier
/auth/auth renders LoginAsSupplierComponent. Internal staff arrive with a
pre-issued session token, which is written straight to localStorage and the
standard userRequested pipeline takes over. The supplier sees the identical
application; permissions are calculated from their real user object.
Auth models
| Model | Contents |
|---|---|
|
Identity, |
|
~40 supplier state flags returned by |
|
|
|
Name, DOB, phone, email, tax id, residential address. |
|
Legal name, business type, incorporation state, owner SSN, EIN, start date, business address. |
|
|
|
|
|
Legacy, unused in supplier flows. |
|
Dashboard notification payloads. |
|
Legacy template model. |
Field-level detail: Model Reference.
Related pages
-
Auth Slice — actions, reducers, selectors