API Authentication
This page explains how third-party applications authenticate to Muhajir Studio external APIs and which API surfaces are intended for external integrations.
Service Base URLs
Use these production service URLs for API, login, and admin workflows:
| Service | Base URL | Used for |
|---|---|---|
| API | https://api.muhajirstudio.com/ | OIDC endpoints, token exchange, public metadata, and /api/external/*. |
| Main web | https://login.muhajirstudio.com/ | Login, signup, email verification, and consent pages. |
| Admin web | https://admin.muhajirstudio.com/ | Admin application configuration UI. |
For sandbox or staging integrations, use the equivalent service URLs provided by your Muhajir Studio contact.
API Base URL
Use the API base URL for the target environment and append the documented path.
Production external current-user URL: https://api.muhajirstudio.com/api/external/me.
If your application supports multiple environments, make the service URLs configurable in your own application.
External API Namespace
Third-party integrations should treat /api/external/* as the stable external API namespace.
Do not call first-party session endpoints such as /api/me/* from third-party integrations unless a specific endpoint is explicitly documented as public. First-party endpoints can rely on cookie sessions and internal UI assumptions, while external endpoints are designed for OIDC bearer access tokens.
Bearer Token Authentication
External APIs require an OIDC access token in the Authorization header:
Authorization: Bearer ACCESS_TOKEN
The server accepts only the Bearer scheme. Cookie-only sessions are not accepted by /api/external/me.
The bearer token resolver checks that:
- the
Authorizationheader exists - the scheme is
Bearer - the access token exists in the OIDC access-token store
- the access token is not expired
- the access token is associated with a user
If any of these checks fail, external APIs return:
{
"error": "UNAUTHORIZED"
}
with HTTP status 401.
Required Scopes
Endpoint-specific scope checks happen after bearer authentication. For example, GET /api/external/me requires the openid scope.
If a valid bearer token is missing a required scope, the endpoint returns 403 with missingScopes:
{
"error": "FORBIDDEN",
"missingScopes": ["openid"]
}
Browser CORS Rules
Browser-based third-party apps can call only route-scoped third-party endpoints from registered origins.
Dynamic third-party CORS is enabled for:
POST /api/auth/oauth2/tokenOPTIONS /api/auth/oauth2/token/api/external/*
Allowed browser origins come from registered application allowedWebOrigins values. The server caches the registered-origin list for 60 seconds.
CORS behavior:
| Setting | Value |
|---|---|
| Credentials | false |
| Methods | GET, POST, OPTIONS |
| Allowed headers | Authorization, Content-Type |
| Preflight success status | 204 |
If the browser request has no Origin, or the origin is not registered, dynamic third-party CORS does not allow the request. Register the exact web origin in web-admin before making browser-based token or external API calls.
Public Metadata Endpoints
Some public metadata endpoints support login, consent, and integration setup flows. They do not require an OIDC bearer token.
GET /api/public/oidc/scopes
Returns metadata for supported OIDC scopes:
{
"items": [
{
"name": "openid",
"label": "Verify your identity",
"consentDescription": "Confirm your account identity.",
"developerDescription": "Required OIDC scope. Allows the app to receive a stable subject identifier.",
"claims": ["sub"]
}
]
}
Current scope names are openid, profile, email, offline_access, and permissions.
GET /api/public/applications/{clientId}
Returns user-facing metadata for an OIDC client:
{
"clientId": "client-id",
"clientName": "Example App",
"clientDescription": "Example description",
"clientLogoUrl": "https://cdn.example.com/logo.png",
"postVerificationRedirectPath": "/welcome",
"postVerificationRedirectUri": "https://app.example.com/welcome"
}
The optional redirect_uri query parameter provides caller context. When it is valid for the client, Muhajir Studio uses its origin to derive postVerificationRedirectUri from the application's path-only postVerificationRedirectPath.
Errors:
| Status | Error | Meaning |
|---|---|---|
400 | INVALID_CLIENT_ID | The clientId parameter is invalid. |
404 | NOT_FOUND | No dynamic or static application exists for the client ID. |
500 | INTERNAL_ERROR | Application lookup failed unexpectedly. |
OAuth Token Endpoint
Third-party apps exchange authorization codes and refresh tokens at:
POST /api/auth/oauth2/token
This endpoint is not under /api/external/*, but it is intentionally included in third-party CORS because browser PKCE clients need to call it.
Use application/x-www-form-urlencoded requests. Admin-created applications are Public PKCE clients and do not have a client_secret.
Error Model
External API errors use JSON response bodies with an error string. Some responses include additional fields such as missingScopes.
Common external API errors:
| Status | Error | Meaning |
|---|---|---|
401 | UNAUTHORIZED | Bearer token is missing, malformed, expired, unknown, or not associated with a user. |
403 | FORBIDDEN | Bearer token is valid but lacks a required scope. |
404 | USER_NOT_FOUND | Token subject no longer maps to an existing user. |
500 | INTERNAL_ERROR | Unexpected server error. |
OAuth endpoints follow OAuth error responses such as invalid_request or invalid_grant.
Implementation Checklist
- Use Authorization Code Flow with PKCE to obtain an OIDC access token.
- Store the token according to your app type and threat model.
- Send
Authorization: Bearer ACCESS_TOKENto/api/external/*. - Request only scopes needed by your integration.
- Register browser origins in
allowedWebOriginsbefore calling token or external API endpoints from a browser. - Use
/api/external/mefor third-party current-user data, not first-party/api/me/*endpoints.