Authentication Troubleshooting
Use this guide to diagnose common OIDC, PKCE, CORS, token, and external API failures when integrating with Muhajir Studio.
Start with the Failing Stage
| Stage | Endpoint or page | Most common issue |
|---|---|---|
| Authorization start | https://api.muhajirstudio.com/api/auth/oauth2/authorize | Redirect URI mismatch, missing PKCE, wrong client_id. |
| Login / verification / consent | https://login.muhajirstudio.com/ | User not signed in, email not verified, consent metadata missing. |
| Token exchange | https://api.muhajirstudio.com/api/auth/oauth2/token | Missing or wrong code_verifier, reused code, wrong redirect URI. |
| Browser API call | https://api.muhajirstudio.com/api/external/me | Origin not registered or missing bearer token. |
| External API auth | /api/external/* | Expired token, missing openid, insufficient scopes. |
Redirect URI Mismatch
Symptom:
{
"error": "INVALID_REDIRECT_URI",
"message": "redirect_uri is not registered for this client"
}
Cause:
Muhajir Studio validates the authorize redirect_uri against the application's registered origin/path matrix. The value must be an exact derived URI.
Fix:
- Confirm the
client_idbelongs to the application you are testing. - In
web-admin, confirm the allowed web origin, for examplehttps://app.example.com. - Confirm the redirect path, for example
/auth/callback. - Send the exact full URI:
https://app.example.com/auth/callback. - Do not add query strings, fragments, wildcards, or a trailing slash unless that exact path is registered.
Missing or Invalid PKCE
Symptoms can include OAuth errors such as:
{
"error": "invalid_request",
"error_description": "..."
}
or token exchange failure with invalid_grant.
Fix:
- Authorization requests must include
code_challenge. code_challenge_methodmust beS256.- The token request must include the original
code_verifier. - Generate a fresh verifier/challenge for each login attempt.
- Do not reuse authorization codes.
Plain PKCE challenges are disabled.
Invalid Client or Metadata Loading Errors
Public application metadata is loaded from:
GET /api/public/applications/{clientId}
Common responses:
| Status | Error | Meaning | Fix |
|---|---|---|---|
400 | INVALID_CLIENT_ID | The client ID path parameter is invalid. | Check for copy/paste mistakes. |
404 | NOT_FOUND | No dynamic or static client exists for the ID. | Confirm the app exists and was not deleted. |
500 | INTERNAL_ERROR | Lookup failed unexpectedly. | Retry and contact support if persistent. |
The consent page disables approval when application metadata cannot be loaded.
Browser CORS Mismatch
Symptoms:
- Browser console shows a CORS failure.
- The request works from a server tool but not from the browser.
- No
Access-Control-Allow-Originheader appears for your SPA origin.
Cause:
Third-party browser CORS is route-scoped and origin-scoped. It applies to:
POST /api/auth/oauth2/tokenOPTIONS /api/auth/oauth2/token/api/external/*
It allows only origins registered in allowedWebOrigins, does not allow credentials, and allows Authorization plus Content-Type headers.
Fix:
- Register the exact browser origin, such as
https://spa.example.com. - Do not include a path in the allowed web origin.
- Wait briefly after admin changes; registered CORS origins are cached for
60seconds. - Do not send
credentials: 'include'from a third-party SPA. - Use bearer tokens for
/api/external/*.
Token Exchange Returns invalid_grant
Common causes:
- Authorization code was already used.
- Authorization code expired.
code_verifierdoes not match the originalcode_challenge.redirect_uriin the token request differs from the authorize request.- Refresh token is missing, expired, revoked, or no longer valid.
Fix:
- Restart the login flow with a new PKCE pair.
- Ensure your callback stores and loads the verifier for the same browser/session attempt.
- Send the same
redirect_uristring in authorize and token requests. - On refresh failure, clear stored tokens and sign in again.
External API Returns 401 UNAUTHORIZED
Response:
{
"error": "UNAUTHORIZED"
}
Meaning:
The external API did not receive a usable OIDC bearer access token. Cookie-only sessions are not accepted by /api/external/*.
Fix:
- Send
Authorization: Bearer ACCESS_TOKEN. - Confirm the token is an OIDC access token, not an ID token.
- Confirm the token is not expired.
- Clear local tokens and restart login if the token is unknown or expired.
External API Returns 403 FORBIDDEN
Response:
{
"error": "FORBIDDEN",
"missingScopes": ["openid"]
}
Meaning:
The token is valid but does not include a required scope. GET /api/external/me requires openid; fields such as email, profile, and permissions require their matching scopes.
Fix:
- Check the application's selected scopes in
web-admin. - Ask an admin to add required scopes if needed.
- Start a new login after scope changes so the user receives a token with the updated scope set.
User Gets Stuck Around Email Verification
Muhajir Studio requires signed-in users to verify their email before OIDC authorization completes. The login UI preserves OIDC parameters through login, signup, /verify-email, and the email-verified screen.
Fix:
- Keep the original authorize query parameters intact when deep-linking users back to login or verification pages.
- Ensure the user completes email verification before expecting the authorization callback.
- If the flow restarts, generate a new PKCE verifier and state.
Quick Diagnostic Checklist
- Is the
client_idcorrect and active? - Does
redirect_uriexactly match the registered derived URI? - Is
code_challenge_method=S256present? - Is the token request form-encoded?
- Is
client_secretomitted for Public PKCE clients? - Is the browser
Originregistered for SPA calls? - Are you sending an access token, not an ID token, to
/api/external/*? - Does the token include
openidfor/api/external/me?