Skip to main content
POST
User authentication and sign-in

Body

application/json
email
string<email>
required
Example:

"john.doe@mydomain.com"

password
string<password>
required
Example:

"iLovePria123"

Response

Successful authentication. Returns JWT token and user profile.

Successful signin response shape. Two variants are returned by the same endpoint depending on whether email MFA is required: • JWT issued — { token, profile }. The user is signed in. • MFA challenge — { mfaRequired: true, challengeId, maskedEmail, codeSent?, stepUp? }. The client must POST the 6-digit code to /api/auth/mfa-verify with the challengeId; the verify endpoint then issues the JWT. Discriminate via mfaRequired === true (per Phase 1 design §6.1).

token
string

Signed JWT token. Present when MFA is not required or has just been verified. Include this in subsequent API requests via the x-access-token header or Authorization Bearer header. Expires after 6 hours (configurable via JWT_VALIDITY_SEC). Automatically refreshed on profile load (sliding session).

Example:

"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2NDMwNzM2ZmQ2MmQ2NTAwNDA0MjA2NzQiLCJlbWFpbCI6ImpvaG4uZG9lQG15ZG9tYWluLmNvbSIsImN1c3RvbWVySWQiOiJjdXNfTnh4eHh4eCIsImFjY291bnRUeXBlIjoidXNlciIsInNlc3Npb25JZCI6InMlM0FhYmMxMjMiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MTcwMDA4NjQwMH0.signature"

profile
object
brandingSwitch
object

Outcome of a branded-link switch attempt. Present only when the request carried a brandingId (an institution publicId from a /login?brandingId= link). The hint never grants access: switched requires an active membership on the twin (or platform-operator status) and an active parent account. Clients clear the stored hint on switched/already and show the no-access notice on refused.

mfaRequired
boolean

When true, the response is an MFA challenge — no JWT issued. Client should redirect to the MFA verify screen with the challengeId.

Example:

true

challengeId
string

MongoDB ObjectId of the issued mfaChallenge. Only present when mfaRequired: true. POST this to /api/auth/mfa-verify alongside the 6-digit code.

Example:

"6856fa89cbafcff8d98680f5"

maskedEmail
string

Partially-masked email address the verification code was sent to (for the verify-screen "code sent to …" prompt). Only present when mfaRequired: true.

Example:

"j*****e@example.com"

codeSent
boolean

false when the challenge comes from an SDK / Canvas launch (/api/auth/autosignup with institution_id or lticontextid): no code has been emailed yet. Show a "Send me a code" action that calls /api/auth/mfa-resend (the first send is not subject to the 30-second wait), then the code entry. A repeated launch of the same Digital Twin and course from the same network within the challenge's lifetime answers with the same challengeId, so a code already emailed keeps working; a launch of another Digital Twin or course, or from another network, gets its own challenge (a network keeps at most three pending launch challenges of a person — a fourth replaces the oldest). Absent or true means the code was emailed.

Example:

false

stepUp
boolean

true when the sign-in asks for a code before any session is opened — an embedded / Canvas launch, or a provider sign-in, of an account that needs a second proof first. Comes with codeSent: false: show "Send me a code" (/api/auth/mfa-resend), then the code entry; /api/auth/mfa-verify then signs the person in — on a launch, to the launched Digital Twin and course. Absent or false otherwise.

Example:

true