chore(LOY-445): remove ENABLE_DTMC flag & add documentation * chore(LOY-445): remove ENABLE_DTMC flag & add documentation Approved-by: Matilda Landström
266 lines
7.0 KiB
Markdown
266 lines
7.0 KiB
Markdown
# DTMC (Digital Team Member Card) Flow Documentation
|
|
|
|
## Overview
|
|
|
|
The DTMC feature allows existing Scandic Friends members to link their employee
|
|
status to their account by authenticating with Microsoft Entra ID.
|
|
This provides employees access to additional benefits.
|
|
|
|
## Current Implementation Architecture
|
|
|
|
### Separate Auth Configuration Approach
|
|
|
|
We use a completely separate auth configuration to avoid session conflicts between:
|
|
|
|
- **Curity**: `auth.ts`
|
|
- Regular user authentication.
|
|
- **DTMC Auth**: `auth.dtmc.ts`
|
|
- Short-lived (10min) session specifically for employee verification.
|
|
|
|
### Key Files & Responsibilities
|
|
|
|
#### Flow Handlers
|
|
|
|
- `app/[lang]/(live)/(public)/dtmc/route.ts`
|
|
- Microsoft auth initiation.
|
|
- `app/api/web/auth/dtmc/route.ts`
|
|
- Employee linking callback handler with API integration.
|
|
|
|
#### Core Authentication
|
|
|
|
- `auth.dtmc.ts`
|
|
- Microsoft Entra ID provider configuration, JWT/session callbacks.
|
|
- `app/api/web/auth/[...nextauth]/route.ts`
|
|
- Routes Microsoft requests to DTMC handlers.
|
|
|
|
#### API Integration
|
|
|
|
- `packages/trpc/lib/api/endpoints.ts`
|
|
- API endpoint definitions including TeamMemberCard.
|
|
- `server/routers/user/output.ts`
|
|
- Profile schema with employmentDetails.
|
|
- `utils/user.ts`
|
|
- Employment utility functions.
|
|
|
|
#### UI Components
|
|
|
|
- `apps/scandic-web/components/MyPages/DigitalTeamMemberCard/index.tsx`
|
|
- Main card component.
|
|
- `apps/scandic-web/components/MyPages/DigitalTeamMemberCard/Alert/index.tsx`
|
|
- Banner shown on the overview page for employee's who have just linked their account.
|
|
|
|
#### Configuration
|
|
|
|
- `constants/routes/dtmc.ts` - Route definitions
|
|
- `components/DigitalTeamMemberCard/EmployeeBenefits/CallToActions/index.tsx`
|
|
- "Link Employment" buttons used within the Employee Benefits page
|
|
(a Contentstack "content page") to initiate the linking process.
|
|
|
|
## Technical Flow
|
|
|
|
### 1. User Journey
|
|
|
|
```
|
|
User (Curity authenticated) → Employee Benefits page → "Link Employment" button →
|
|
Microsoft Auth → Employee ID extraction → API linking → Success redirect
|
|
```
|
|
|
|
### 2. Detailed Technical Sequence
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant U as User
|
|
participant C as Curity Session
|
|
participant D as DTMC Route
|
|
participant M as Microsoft Auth
|
|
participant J as JWT Callback
|
|
participant S as Session Callback
|
|
participant H as DTMC Handler
|
|
participant A as Employee API
|
|
|
|
U->>C: Already authenticated (Curity)
|
|
U->>D: Click "Link Employment" → /[lang]/dtmc
|
|
D->>M: signIn("microsoft-entra-id")
|
|
M->>U: Microsoft login prompt
|
|
U->>M: Authenticate with corporate credentials
|
|
M->>J: Profile with user.employeeid
|
|
J->>J: Store employeeId directly in token
|
|
J->>S: Expose as session.employeeId
|
|
S->>H: Callback to /api/web/auth/dtmc
|
|
H->>H: Validate both Curity + DTMC sessions
|
|
H->>A: Call linkEmployeeToUser(employeeId)
|
|
A->>H: Success response
|
|
H->>U: Redirect to overview with success banner
|
|
```
|
|
|
|
### 3. Code Implementation Details
|
|
|
|
#### DTMC Auth Configuration (`auth.dtmc.ts`)
|
|
|
|
```typescript
|
|
// Separate session cookie to avoid conflicts
|
|
cookies: {
|
|
sessionToken: {
|
|
name: "dtmc.session-token",
|
|
},
|
|
}
|
|
|
|
// Short-lived session for security
|
|
session: {
|
|
strategy: "jwt",
|
|
maxAge: 10 * 60, // 10 minutes
|
|
}
|
|
|
|
// Storage of employeeId
|
|
jwt({ account, profile, token }) {
|
|
if (account?.provider === "microsoft-entra-id") {
|
|
const employeeId = profile["user.employeeid"]
|
|
return {
|
|
access_token: "", // Empty to save cookie size
|
|
loginType: "dtmc",
|
|
employeeId,
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Route Routing (`[...nextauth]/route.ts`)
|
|
|
|
Routes Microsoft requests to DTMC handlers by checking if the pathname contains "microsoft-entra-id".
|
|
|
|
#### Auth Initiation (`/dtmc/route.ts`)
|
|
|
|
```typescript
|
|
// Starts Microsoft signin with callback redirect
|
|
const redirectUrl = await signIn(
|
|
"microsoft-entra-id",
|
|
{
|
|
redirectTo: `${env.PUBLIC_URL}${dtmcApiCallback}`,
|
|
redirect: false,
|
|
},
|
|
{
|
|
prompt: "login",
|
|
}
|
|
)
|
|
```
|
|
|
|
#### Callback Handler (`/api/web/auth/dtmc/route.ts`)
|
|
|
|
```typescript
|
|
// Validates dual sessions and processes linking
|
|
const dtmcSession = await dtmcAuth() // Microsoft session
|
|
const session = await auth() // Curity session
|
|
|
|
// Both sessions required for security
|
|
if (!isValidSession(session) || !isValidSession(dtmcSession)) {
|
|
// Redirect to error page
|
|
}
|
|
|
|
const employeeId = dtmcSession.employeeId
|
|
await linkEmployeeToUser(employeeId, accessToken)
|
|
```
|
|
|
|
## Routes & URLs
|
|
|
|
### User-Facing Routes
|
|
|
|
- `/[lang]/dtmc` - Microsoft auth initiation
|
|
- `/[lang]/link-employment-error` - Error handling page
|
|
- `/[lang]/employee-benefits` - Employee benefits overview
|
|
|
|
### API Routes
|
|
|
|
- `/api/web/auth/dtmc` - Employee linking callback handler
|
|
- `/api/web/auth/[...nextauth]` - NextAuth routing (handles Microsoft provider)
|
|
|
|
## API Integration Details
|
|
|
|
### TeamMemberCard Endpoint
|
|
|
|
```typescript
|
|
// Added to packages/trpc/lib/api/endpoints.ts
|
|
export namespace v2 {
|
|
export namespace Profile {
|
|
export function teamMemberCard(employeeId: string) {
|
|
return `${profile}/${employeeId}/TeamMemberCard`
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Profile Schema Extension
|
|
|
|
```typescript
|
|
// Added to server/routers/user/output.ts
|
|
export const employmentDetailsSchema = z
|
|
.object({
|
|
employeeId: z.string(),
|
|
location: z.string(),
|
|
country: z.string(),
|
|
retired: z.boolean(),
|
|
})
|
|
.optional()
|
|
```
|
|
|
|
### Employee Utility Functions
|
|
|
|
```typescript
|
|
// Added to utils/user.ts
|
|
export function isEmployeeLinked(user: User): boolean
|
|
export function getEmployeeInfo(user: User)
|
|
export function canUseEmployeeBenefits(user: User): boolean
|
|
```
|
|
|
|
### Status Code Handling
|
|
|
|
- **200/202**: Success → Continue to overview page
|
|
- **400/404**: Client errors → "unable_to_verify_employee_id" error page
|
|
- **500**: Server error → Default error message
|
|
- **Network errors**: → Default error message
|
|
|
|
## Digital Team Member Card Behavior
|
|
|
|
```typescript
|
|
// Current implementation
|
|
const hasEmploymentData = isEmployeeLinked(user)
|
|
|
|
if (!hasEmploymentData) {
|
|
return null
|
|
}
|
|
return <DigitalTeamMemberCardClient user={user} />
|
|
```
|
|
|
|
## Testing Checklist
|
|
|
|
### Happy Path
|
|
|
|
- [x] User has valid Curity session
|
|
- [x] Microsoft auth extracts employee ID successfully
|
|
- [x] Both sessions validated in callback handler
|
|
- [x] Employee linking API call succeeds
|
|
- [x] User redirected to overview with success banner
|
|
- [x] Original Curity session remains functional
|
|
- [x] Digital Team Member Card displays with employment data
|
|
|
|
### Error Scenarios
|
|
|
|
- [x] Missing Curity session during flow
|
|
- [x] Microsoft auth failure/cancellation
|
|
- [x] Missing employee ID in Microsoft profile
|
|
- [x] Employee API failure scenarios
|
|
- [x] DTMC session expiration
|
|
- [x] Status code mapping (400/404/500/network errors)
|
|
|
|
### Security Validation
|
|
|
|
- [x] No employee ID in browser network logs
|
|
- [x] No employee ID in URL parameters
|
|
- [x] Dual session architecture working
|
|
- [x] Proper session validation in callback
|
|
- [x] Short-lived DTMC session (10 minutes) for security
|
|
|
|
### UI/UX Validation
|
|
|
|
- [x] Card shows real data when employment details exist
|
|
- [x] Proper fallbacks for missing employment data fields
|