|### Overview
|
|When a new OBP local user is created, they may be required to validate their email address before they can log in.
|This is controlled by the `authUser.skipEmailValidation` property (default: `false`).
|
|When email validation is enabled, the user receives an email containing a signed JWT token with a validation link.
|The user clicks the link, and the App (portal) extracts the token and calls the API to complete the validation.
|
|### Props
|
|The following properties are involved:
|
|- `authUser.skipEmailValidation` — Set to `true` to skip email validation entirely (default: `false`). Currently: `false`
|- `portal_external_url` — **Required.** The base URL of your frontend/portal application. Used to construct the validation link in the email. For example: `portal_external_url=https://your-portal.example.com`. Currently: `https://obp-portal-sandbox.nmbbank.co.tz`
|- `email_validation_token_expiry_minutes` — Expiry time for the validation JWT token in minutes (default: `1440` i.e. 24 hours). Currently: `1440`
|
|### Step 1: User Creation
|
|A user can be created via:
|
|**POST /obp/v6.0.0/users** (no authentication required)
|
|Request body:
|
| {
| "username": "user@example.com",
| "password": "Str0ng!Password",
| "first_name": "Jane",
| "last_name": "Doe",
| "email": "user@example.com"
| }
|
|If `authUser.skipEmailValidation=false`, the API will:
|
|1. Create the user with `validated=false`
|2. Generate a signed JWT token containing the user's unique ID as the subject, with a configurable expiry
|3. Construct a validation link: `{portal_external_url}/user-validation?token={JWT}`
|4. Send an email to the user with the validation link
|
|The user or the legacy Lift signup form can also trigger validation emails. In all cases, the same JWT-based token is used.
|
|### Step 2: Email Validation
|
|**POST /obp/v6.0.0/users/email-validation** (no authentication required)
|
|Request body:
|
| {
| "token": "eyJhbGciOiJIUzI1NiJ9..."
| }
|
|Response (201):
|
| {
| "user_id": "5995d6a2-01b3-423c-a173-5481df49bdaf",
| "email": "user@example.com",
| "username": "user@example.com",
| "provider": "https://your-api.example.com",
| "validated": true,
| "message": "Email validated successfully"
| }
|
|Error responses:
|
|- **400** — Invalid JSON format or empty token
|- **404** — Invalid or expired JWT token (bad signature, expired, or user not found)
|- **400** — User email is already validated
|
|This endpoint:
|
|1. Verifies the JWT signature (HMAC) and checks the expiry time
|2. Extracts the unique ID from the JWT subject
|3. Looks up the user by unique ID
|4. Sets the user's validated status to `true`
|5. Resets the unique ID (invalidating the token — it is single-use)
|6. Grants default entitlements to the user
|
|### Token Security
|
|- The token is a **signed JWT** (HMAC-SHA256) — it cannot be forged without the server's shared secret.
|- The token has a **configurable expiry** (default: 24 hours) set via `email_validation_token_expiry_minutes`.
|- The token is **single-use** — after validation, the unique ID is reset, so the same token cannot be used again.
|
|### Typical App Flow
|
|1. User submits registration form
|2. App calls POST /obp/v6.0.0/users
|3. App shows "Check your email for a validation link"
|4. User clicks link in email, App opens at `/user-validation?token={JWT}`
|5. App extracts the token from the URL query parameter
|6. App calls POST /obp/v6.0.0/users/email-validation with the token
|7. App shows "Email validated successfully. Please log in."
|
|