Authentication
The Odento API supports two authentication methods: JWT tokens for user-facing applications and API keys for server-to-server integrations. All authenticated requests must include valid credentials.
JWT Authentication
JWT (JSON Web Token) authentication is used for user-facing applications where a user logs in with their credentials and receives a short-lived access token and a long-lived refresh token.
Login Flow
Send a POST request to the /auth/login endpoint with the user's email and password. On success, you'll receive both tokens:
curl -X POST https://api.odento.app/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "dr.sharma@dentalkare.in",
"password": "your-secure-password"
}'{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwiaWF0IjoxNzMyNzAxMjAwLCJleHAiOjE3MzI3MDEyOTB9.signature",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwidHlwIjoxNzMyNzAxMjAwLCJleHAiOjE3MzUyMDcyMDB9.signature",
"token_type": "Bearer",
"expires_in": 900,
"user": {
"id": "usr_abc123",
"email": "dr.sharma@dentalkare.in",
"name": "Dr. Priya Sharma",
"role": "dentist"
}
}
}Try It Out
Token Lifetimes
Access tokens expire in 15 minutes (900 seconds). Refresh tokens expire in 30 days. Always store refresh tokens securely and never expose them in client-side code.
Using the Access Token
Include the access token in the Authorization header as a Bearer token for all authenticated requests:
curl -X GET https://api.odento.app/api/v1/patients \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwiaWF0IjoxNzMyNzAxMjAwLCJleHAiOjE3MzI3MDEyOTB9.signature"Refreshing Tokens
When the access token expires, use the refresh token to obtain a new pair without requiring the user to log in again:
curl -X POST https://api.odento.app/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwidHlwIjoxNzMyNzAxMjAwLCJleHAiOjE3MzUyMDcyMDB9.signature"
}'{
"success": true,
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwiaWF0IjoxNzMyNzAyMDAwLCJleHAiOjE3MzI3MDIwOTB9.new_signature",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfYWJjMTIzIiwidHlwIjoxNzMyNzAyMDAwLCJleHAiOjE3MzUyMTIwMDB9.new_signature",
"token_type": "Bearer",
"expires_in": 900
}
}Each refresh invalidates the previous refresh token and issues a new one. This rotation mechanism ensures compromised tokens are quickly rendered useless.
Logout
To revoke the current session, call the logout endpoint with the access token:
curl -X POST https://api.odento.app/api/v1/auth/logout \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."{
"success": true,
"data": {
"message": "Session revoked successfully."
}
}API Key Authentication
API keys are the recommended authentication method for server-to-server integrations, automation scripts, and backend services. Unlike JWT tokens, API keys do not expire automatically and do not require a refresh flow.
API Key Format
Each API key consists of two parts:
- Key ID — Prefixed with
ok_live_followed by 24 alphanumeric characters. Example:ok_live_abc123def456ghi789jkl012 - Key Secret — Prefixed with
os_followed by 48 alphanumeric characters. Example:os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567
Keep Your Secret Safe
The key secret is shown only once at creation time. Store it securely — we cannot recover it. If compromised, revoke the key immediately in the developer portal.
Using API Keys
Pass both the key ID and secret as HTTP headers in every request:
curl -X GET https://api.odento.app/api/v1/patients \
-H "X-API-Key-ID: ok_live_abc123def456ghi789jkl012" \
-H "X-API-Key-Secret: os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567"Getting API Keys
To create an API key:
- Log in to the developer portal
- Navigate to API Keys in the sidebar
- Click Create New Key
- Choose the modules and scopes the key should have access to
- Copy the key ID and secret immediately — the secret is shown only once
You can also create keys programmatically via the API Keys endpoint:
curl -X POST https://api.odento.app/api/v1/devportal/keys \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"name": "Production Integration",
"modules": ["patients", "appointments", "billing"],
"scopes": ["read", "write"]
}'{
"success": true,
"data": {
"key_id": "ok_live_abc123def456ghi789jkl012",
"key_secret": "os_abc123def456ghi789jkl012mno345pqr678stu901vwx234yzab567",
"name": "Production Integration",
"modules": ["patients", "appointments", "billing"],
"scopes": ["read", "write"],
"created_at": "2025-01-15T10:30:00Z"
}
}Scope-Based Authorization
Each API key is assigned a set of modules and scopes. Modules determine which API areas the key can access, and scopes determine what operations are permitted within those modules.
Available Scopes
| Scope | Description |
|---|---|
| read | Read access to module resources (GET requests) |
| write | Create and update resources (POST, PUT, PATCH) |
| delete | Delete resources (DELETE requests) |
| webhook.manage | Manage webhook endpoints and subscriptions |
If a key attempts to access a module or scope it doesn't have, the API returns a MODULE_NOT_ALLOWED or SCOPE_NOT_APPROVED error:
{
"success": false,
"error": {
"code": "MODULE_NOT_ALLOWED",
"message": "Your API key does not have access to the 'billing' module."
}
}Best Practices
- Never commit keys to version control. Use environment variables or a secrets manager.
- Use the principle of least privilege. Only grant the modules and scopes your integration needs.
- Rotate keys regularly. Create new keys, update your integration, then revoke old keys.
- Use JWT for user-facing apps and API keys for server-to-server communication.
- Store refresh tokens securely — they are valid for 30 days and can be used to mint new access tokens.
- Handle token expiry gracefully — proactively refresh before expiry or catch 401 responses and refresh.
Was this page helpful?
Help us improve our documentation