Skip to main content

Self-Service Federation Lock

This document explains the architectural concepts behind the Self-Service Federation Lock in Framework M, focusing on why it is enforced, the security validations behind it, and how the flow matches the Single Source of Truth design.


1. Concept: Single Source of Truth

When an application operates in Federated Mode (Mode B/Mode C, where users authenticate via external corporate providers like Okta, Keycloak, or Azure AD), the external identity provider is the Single Source of Truth (SSoT) for user data.

If users were allowed to update their profile info (such as email, full name, or phone number) directly inside Framework M:

  • It would create data drift: changes would not sync back upstream to the corporate IdP.
  • On the next social login, the JIT provisioning mechanism would see mismatching data, causing identity linking conflicts or reverting the user's edits with fresh upstream token data.

To prevent this drift, Framework M enforces a complete lock on local self-service inputs whenever the user is logged in via a federated strategy.


2. Redirection and UI Context Locks

Redirection to Upstream

If an authenticated user has an active federated session (e.g. upstream_profile_url is populated in their context from the active OIDC provider configuration block):

  1. In the frontend Desk shell, the standard profile editing fields are locked and rendered as read-only.
  2. The UI renders a prominent "Edit Profile on [Provider]" button that points to the configured upstream_profile_url.
  3. If the user attempts to directly hit the profile update API endpoints (e.g. PUT /api/v1/auth/me), the web adapter rejects the request immediately with 405 Method Not Allowed or 400 Bad Request.

3. Verification Sequence Diagrams

Email Verification Loop (Local Mode)

For local accounts, updating email requires verifying ownership first to prevent hijacking and spam database pollution.

sequenceDiagram
actor User
participant App as Desk Frontend
participant API as Web API
participant Cache as Cache Store
participant SMTP as SMTP / Email Adapter

User->>App: Request email update (new_email)
App->>API: POST /request-email-update
API->>API: Validate new_email is unique
API->>Cache: Store token -> {"user_id": uid, "new_email": new_email} (TTL=1hr)
API->>SMTP: Queue verification mail with token link
SMTP-->>User: Delivers verification mail
API-->>App: 200 OK (Verification sent)
User->>API: GET /confirm-email-update/{token}
API->>Cache: Retrieve & delete token details
API->>API: Update LocalUser.email (system context bypass)
API-->>User: Redirect to profile (Success message)

Phone (OTP) Verification Loop (Local Mode)

Phone verification uses SMS gateways for verification-driven updates.

sequenceDiagram
actor User
participant App as Desk Frontend
participant API as Web API
participant Cache as Cache Store
participant SMS as SMS Gateway Adapter

User->>App: Request phone update (new_phone)
App->>API: POST /request-phone-update
API->>API: Validate new_phone is unique
API->>Cache: Store OTP -> {"code": 123456, "new_phone": new_phone} (TTL=5m)
API->>SMS: Dispatch OTP message
SMS-->>User: Receives OTP code
API-->>App: 200 OK (OTP Sent)
User->>App: Inputs OTP code
App->>API: POST /confirm-phone-update {"otp": "123456"}
API->>Cache: Verify and pop OTP code
API->>API: Update LocalUser.phone_number (system context bypass)
API-->>App: 200 OK (Updated)