Authentication
This guide explains how to integrate with the Mindoo API using the OAuth 2.0 authorization code flow with PKCE (proof key for code exchange). This is the recommended approach for securely accessing user data on behalf of your users.
Prerequisites
Before you begin, make sure you have:
- A registered OAuth application with Mindoo (contact support@mindoo.ai to obtain your
client_id). Only approved clients will be able to consume the API through OAuth. - A configured redirect URI for your application
Overview
The OAuth flow consists of three main steps:
- Authorization: Redirect the user to the Mindoo authorization endpoint to obtain an authorization code
- Token exchange: Exchange the authorization code for tokens
- API access: Use the
id_tokento authenticate API requests
Step 1: Obtain user authorization
Redirect your user to the Mindoo authorization endpoint to initiate the OAuth flow. The link to this endpoint should be given to you by the Mindoo support team.
Authorization endpoint
GET https://api.mindoo.ai/auth/oauth2/authorize
Required parameters
| Parameter | Description |
|---|---|
response_type |
Must be code |
client_id |
Your OAuth application’s client ID |
redirect_uri |
The URL where users will be redirected after authorization (must match your registered redirect URI) |
scope |
Space-separated list of requested scopes |
state |
A random string to prevent CSRF attacks (you should verify this value when the user is redirected back) |
code_challenge |
A PKCE code challenge (Base64 URL-encoded SHA-256 hash of a random code verifier) |
code_challenge_method |
Must be S256 |
Available scopes
| Scope | Description |
|---|---|
openid |
Required for OpenID Connect |
profile |
Access to user profile information |
email |
Access to user email address |
offline_access |
Request a refresh token for long-lived access |
read |
Read access to API resources |
write |
Write access to API resources |
At minimum, you should request the openid, email, read, and write scopes to consume the API.
It’s also adviced to include the offline_access scope in order to obtain new tokens without requiring user interaction.
Example authorization URL
https://api.mindoo.ai/auth/oauth2/authorize?response_type=code&client_id=TkkjdhfiuhibksufiniutUgUQRjQlREwS&redirect_uri=https://your-website.com/api/oauth/callback&scope=openid%20profile%20offline_access%20email%20read%20write&state=<RANDOM_STATE_TO_PREVENT_XSRF_ATTACK>&code_challenge=<UNIQUE_CODE_CHALLENGE>&code_challenge_method=S256
Generating the PKCE code challenge
The PKCE flow requires you to generate a code verifier and its corresponding code challenge:
Node.js example
import crypto from "node:crypto"
const codeVerifier = crypto
.randomBytes(32)
.toString("base64")
const codeChallenge = crypto
.createHash("sha256")
.update(codeVerifier)
.digest("base64url")
Python example
import base64
import hashlib
import secrets
code_verifier = base64.b64encode(secrets.token_bytes(32)).decode()
digest = hashlib.sha256(code_verifier.encode()).digest()
code_challenge = base64.urlsafe_b64encode(digest).decode().rstrip("=")
Store the code_verifier securely. You will need it in Step 2 to exchange the authorization code for tokens.
Handling the callback
After the user authorizes your application, they will be redirected to your redirect_uri with the following query parameters:
code: The authorization code (valid for a short time)state: The state value you provided (verify this matches your original value)
Example callback URL:
https://your-website.com/api/oauth/callback?code=abc123&state=your_random_state
Always verify that the state parameter matches the value you sent in the authorization request to prevent CSRF attacks.
Step 2: Exchange the authorization code for tokens
Once you have the authorization code, exchange it for tokens by making a POST request to the token endpoint.
Token endpoint
POST https://api.mindoo.ai/auth/oauth2/token
Content-Type: application/x-www-form-urlencoded
Request body parameters
| Parameter | Description |
|---|---|
grant_type |
Must be authorization_code |
code |
The authorization code received from the callback |
redirect_uri |
The same redirect URI used in the authorization request |
client_id |
Your OAuth application’s client ID |
code_verifier |
The PKCE code verifier you generated in Step 1 |
Example request
curl -X POST https://api.mindoo.ai/auth/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=<AUTHORIZATION_CODE>" \
-d "redirect_uri=https://your-website.com/api/oauth/callback" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "code_verifier=<YOUR_CODE_VERIFIER>"
Response
A successful response returns a JSON object containing:
{
"access_token": "mrIFnBgEZhujFqGOXr...",
"expires_in": 3600,
"expires_at": 1768476855,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "openid profile offline_access email read write",
"refresh_token": "uvTyyNoCtyPwpUFkTtCIWR...",
"token_type": "Bearer"
}
| Field | Description |
|---|---|
access_token |
The access token (not used yet) |
id_token |
A JWT containing user identity information and granted scopes, used to authenticate API requests |
refresh_token |
A long-lived token used to obtain new tokens (only present if offline_access scope was requested) |
token_type |
Always Bearer |
expires_in |
Token validity in seconds |
scope |
Space-separated list of granted scopes |
Store the refresh_token securely in your database. You will need it to obtain new tokens when the current one expires.
Step 3: Use the token to access the API
Use the id_token to authenticate your API requests by including it in the Authorization header.
Verifying API access
Use the GET /api/verify-token endpoint to verify that your token works and to see which user and organization you are authenticated as.
curl -X GET https://api.mindoo.ai/verify-token \
-H "Authorization: Bearer <ID_TOKEN>"
You can optionally specify which organization to authenticate as by setting the x-organization-id header. The user must be a member of the specified organization.
curl -X GET https://api.mindoo.ai/verify-token \
-H "Authorization: Bearer <ID_TOKEN>" \
-H "x-organization-id: <ORGANIZATION_ID>"
Example response:
{
"organization": {
"id": "abc123",
"name": "Example Hospital"
},
"user": {
"email": "doctor@example.com",
"firstName": "John",
"type": "oauth"
}
}
Refreshing tokens
When the id_token expires, use the refresh_token to obtain new tokens without requiring user interaction.
Refresh token request
POST https://api.mindoo.ai/auth/oauth2/token
Content-Type: application/x-www-form-urlencoded
Request body parameters
| Parameter | Description |
|---|---|
grant_type |
Must be refresh_token |
refresh_token |
The refresh token from your database |
client_id |
Your OAuth application’s client ID |
Example request
curl -X POST https://api.mindoo.ai/auth/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=<YOUR_REFRESH_TOKEN>" \
-d "client_id=<YOUR_CLIENT_ID>"
Response
The response contains a new set of tokens:
{
"access_token": "mrIFnBgEZhujFqGOXr...",
"expires_in": 3600,
"expires_at": 1768476855,
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "openid profile offline_access email read write",
"refresh_token": "uvTyyNoCtyPwpUFkTtCIWR...",
"token_type": "Bearer"
}
Each refresh request returns a new refresh_token and revokes the previous one. Always update the stored refresh_token in your database with the new value.
Security best practices
Please keep in mind to:
- Store tokens securely. Never expose tokens in client-side code or logs. Store
refresh_tokenencrypted in your database. - Validate the
stateparameter. Always verify thestateparameter matches your original value to prevent CSRF attacks. - Handle token expiration. Implement automatic token refresh before the
id_tokenexpires. - Minimize scope. Only request the scopes your application actually needs.