Exchange patient session code for tokens
- Sandbox: available
- Staging: available
- Production: unknown
Finishes a patient login: exchanges the session code from login/start (or login/mfa) and your PKCE codeVerifier for an access token and a refresh token.
Auth: none. The session code and code verifier prove the earlier steps.
Behaviour
- Ovok redeems the code with Medplum's
oauth2/tokenendpoint (grant_type=authorization_code). - The signed-in profile must be a Patient. A code for any other profile type is refused.
- 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 theprojectandprofile. - Error responses are delayed to take at least one second.
Example
curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Patient/login/token' \ -H 'Content-Type: application/json' \ -d '{ "sessionCode": "<sessionCode from login/start>", "codeVerifier": "<your codeVerifier>" }'application/json- body
sessionCode*stringcodeVerifier*stringAccess token, refresh token, expiry, project and profile.
application/json- response
accessToken*stringBearer access token. Expires in 1 hour.
refreshToken?stringRefresh token.
expiresIn?integerToken expiration.
3600project*profile*curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Patient/login/token' \ -H 'Content-Type: application/json' \ -d '{ "sessionCode": "string", "codeVerifier": "string"}'{ "accessToken": "string", "refreshToken": "string", "expiresIn": 3600, "project": { "reference": "string", "display": "string" }, "profile": { "reference": "string", "display": "string" }}Start patient login POST
Starts a patient login for one tenant: checks the email and password and returns either a session code to exchange for tokens or, when the user has MFA enrolled, a login ID for the MFA step. **Auth:** none. The tenant is named by `tenantCode`. **Scope:** the project that owns `tenantCode`. ## Behaviour - This is step 1 of a PKCE login. Generate a random `codeVerifier`, send its S256 hash as `codeChallenge` here, and send the `codeVerifier` itself to `POST /auth/tenant/Patient/login/token`. - The account must be a Patient of the tenant's project. A Practitioner with the same email cannot log in here. - `PATIENT_LOGIN_ENABLED` on the project must not be `false` (it defaults to on). - Response `nextStep`: - `token`: no MFA. Pass `sessionCode` to `login/token`. - `mfa`: the user has MFA enrolled. Pass `loginId` and the current TOTP code to `POST /auth/tenant/Patient/login/mfa`. - A wrong email, an unknown account, an account without a password and a wrong password all give the same 401 `Invalid email or password.` - After 5 failed sign-ins for one email within 15 minutes, that email's sign-ins answer 429 with `Retry-After` for 15 minutes, the right password included, whether or not the email has an account. A successful sign-in resets the count. - Error responses are delayed to take at least one second. ## Example ```bash curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Patient/login/start' \ -H 'Content-Type: application/json' \ -d '{ "email": "max.mustermann@example.com", "password": "your-password", "tenantCode": "my-medical-project", "codeChallenge": "<base64url S256 hash of your codeVerifier>" }' ```
Verify patient MFA code POST
Verifies the TOTP code of a patient who has MFA enrolled, after `login/start` answered `nextStep: "mfa"`. Returns the session code for `login/token`. **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": ... }`. Pass `sessionCode` to `POST /auth/tenant/Patient/login/token`. - Error responses are delayed to take at least one second. ## Example ```bash curl -X POST 'https://api.sandbox.ovok.com/auth/tenant/Patient/login/mfa' \ -H 'Content-Type: application/json' \ -d '{ "loginId": "c3499c27-2973-0a7f-807e-fb8676a92dcb", "mfaToken": "123456" }' ```