Tenant Authentication

Verify practitioner MFA code

  • Sandbox: available
  • Staging: available
  • Production: unknown
POST
/auth/tenant/Practitioner/login/mfa

Verifies the TOTP code of a practitioner who has MFA enrolled, after login/start answered nextStep: "mfa". Returns the session code for login/token and the list of tenants the practitioner can enter.

Auth: none. The loginId from login/start identifies the login.

Behaviour

  • mfaToken must equal the current TOTP code generated from the user's MFA secret.
  • On success the login is marked MFA-verified and the response is { "nextStep": "token", "sessionCode": ..., "profiles": [...] }. profiles is the same list login/start returns without MFA.
  • Pass sessionCode and one tenantCode from profiles to POST /auth/tenant/Practitioner/login/token.
  • Error responses are delayed to take at least one second.

Example

curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Practitioner/login/mfa' \  -H 'Content-Type: application/json' \  -d '{    "loginId": "c3499c27-2973-0a7f-807e-fb8676a92dcb",    "mfaToken": "123456"  }'

Request Body

application/json
  1. body
mfaToken*string
Length6 <= length
loginId*string
Formatuuid

Response Body

A session code for login/token.

application/json
  1. response
nextStep*"token"
Value in"token"
sessionCode*string
profiles*array<>
Example Request
curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Practitioner/login/mfa' \  -H 'Content-Type: application/json' \  -d '{  "mfaToken": "string",  "loginId": "8f568ecd-0198-4d41-91e2-cb501f4140f6"}'
Example Response
{  "nextStep": "token",  "sessionCode": "string",  "profiles": [    {      "project": null,      "profile": null,      "tenantCode": "string",      "admin": true,      "isMainProject": true,      "parentProjectId": "string"    }  ]}

Exchange practitioner session code for tokens POST

Finishes a practitioner login into one tenant: binds the session to the practitioner's membership in that tenant, then exchanges the session code and your PKCE `codeVerifier` for an access token and a refresh token. **Auth:** none. The session code and code verifier prove the earlier steps. **Scope:** the project that owns `tenantCode`. Pick it from the `profiles` returned by `login/start` or `login/mfa`. ## Behaviour - `PRACTITIONER_LOGIN_ENABLED` on the chosen project must not be `false` (it defaults to on). - The practitioner must have a membership in the chosen tenant. Ovok points the pending login at that membership before the code is redeemed, so the tokens are scoped to that project. - Ovok redeems the code with Medplum's `oauth2/token` endpoint (`grant_type=authorization_code`). - If the account was scheduled for deletion (`DELETE /auth/delete`), logging in cancels the deletion. - The response holds `accessToken`, `refreshToken`, `expiresIn` (seconds) and references to the `project` and `profile`. - Error responses are delayed to take at least one second. ## Example ```bash curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Practitioner/login/token' \ -H 'Content-Type: application/json' \ -d '{ "sessionCode": "<sessionCode from login/start>", "codeVerifier": "<your codeVerifier>", "tenantCode": "my-medical-project" }' ```

Register a practitioner POST

Registers a new practitioner account in a tenant and returns its tokens, so the user is signed in straight away. **Auth:** none. The tenant is named by `tenantCode`. **Scope:** the project that owns `tenantCode`. ## Behaviour - The project setting `PRACTITIONER_REGISTRATION_ENABLED` must be `true`. It is off unless set. - The new membership gets the project's default practitioner access policy: the text setting `DEFAULT_PRACTITIONER_ACCESS_POLICY`, else `CLINICIAN_INVITE_ACCESS_POLICY`. Without a valid one, nothing is created and the answer is a 409 with `error: "practitioner_registration_not_configured"`. - An email that already has a practitioner account (a server-wide User) joins this project when the request brings that account's own password: a new practitioner profile and membership, and the password is never changed. It is refused, with nothing written, for any other password, an account with MFA on, an account that is already a practitioner here, and an email that has a patient account in any project. - The password must have at least 12 characters, not counting spaces at either end, and must not be on Ovok's list of common and breached passwords. Any character is allowed and none is required. A refused password answers 422 with the error on `password`. - The User, the Practitioner profile and the membership are written in one atomic step. No email is sent. - Rate limit: 5 requests per minute per IP address. - Error responses are delayed to take at least one second. - A 409 with `practitioner_registration_not_configured` means the project has no practitioner registration setup. - A 429 means more than 5 requests in a minute from your IP address. ## Example ```bash curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Practitioner/register' \ -H 'Content-Type: application/json' \ -d '{ "email": "max.mustermann@example.com", "password": "your-password", "name": "Max", "surname": "Mustermann", "tenantCode": "my-medical-project" }' ```