Quickstart — connect an external app
The shortest complete path for an app that only consumes this Identity Provider: register it, grant a user access, sign in, verify the token. Every step links to the reference page that explains the details.
Nothing here is specific to our stack. This is a standards-compliant OAuth 2.1 authorization server, so any OIDC client library works.
| Issuer | https://admin.fixweb.cloud |
| JWKS | https://admin.fixweb.cloud/.well-known/jwks.json |
| Admin console | https://admin-admin.fixweb.cloud |
Before you start
You need a tenant admin to run step 1 (registering an app is a privileged operation — an app cannot self-register). If you are not an admin, send them your app id and callback URL and ask for step 1 and 2.
Pick two values now and keep them stable:
- an app id (e.g.
jarvis), lowercase, which is also your OAuth
client_id;
- your callback URL (e.g.
https://jarvis.example.com/callback), the exact
absolute URL the IdP is allowed to redirect back to.
1. Register the app (tenant admin)
Console: Apps → Register app, paste the manifest below.
Or over HTTP — see Register an app for the full manifest schema and the accepted admin credentials:
curl -X POST 'https://admin.fixweb.cloud/api/admin/applications/register' \
-H "Authorization: Bearer $ADMIN_ACCESS_TOKEN" \
-H 'content-type: application/json' \
-d '{
"id": "jarvis",
"name": "Jarvis",
"deployable": false,
"url": "https://jarvis.example.com",
"oauth": { "redirect_uris": ["https://jarvis.example.com/callback"] },
"permissions": [
{ "id": "jarvis.chat.read", "label": "Read chat history" }
]
}'
deployable: false means "external app": the platform hosts nothing, it only authenticates your users.
Registering is what makes client_id=jarvis acceptable at /authorize. The gate is strict — an unregistered client_id, or a redirect_uri that is neither declared nor on the app's own host, is rejected with unauthorized_client. See Connect an app.
2. Grant a user access
Registration alone does not let anyone in. Each user needs app:jarvis:access, granted directly, through a role, or through an IdP group.
Console: select the app → Grant to role / user / group. Details and the equivalent API calls: RBAC.
3. Sign the user in (authorization code + PKCE)
Send the user to /authorize, then exchange the code at /token. Generate a fresh code_verifier and a random state per attempt, and reject a callback whose state does not match what you stored — that check is what protects the login against CSRF.
GET https://admin.fixweb.cloud/authorize
?response_type=code
&client_id=jarvis
&redirect_uri=https%3A%2F%2Fjarvis.example.com%2Fcallback
&state=<random, stored client-side>
&code_challenge=<S256 of your verifier>
&code_challenge_method=S256
curl -X POST 'https://admin.fixweb.cloud/token' \
-d grant_type=authorization_code \
-d client_id=jarvis \
-d redirect_uri=https://jarvis.example.com/callback \
-d code=<code from the callback> \
-d code_verifier=<the verifier for this attempt>
You get an ES256 access token and a refresh token. Public clients (SPA, mobile) use PKCE with no client secret. Endpoint reference and the full flow: Integration guide.
4. Verify the token in your backend
Verify the signature against the JWKS, then check iss and aud, and read identity from properties (userID, email, roles, permissions).
aud is your client_id. Skipping it would let a token minted for another app on this IdP pass your checks with that app's grants. Copy-paste examples in PHP and TypeScript: Verifying a token server-side.
Authorize from properties.permissions server-side. Never trust a permission list computed in the browser.
5. When something fails
| Symptom | Cause |
|---|---|
unauthorized_client at /authorize | client_id is not a registered app id, or redirect_uri is not declared. Re-check step 1. |
| Sign-in works, your app says "no access" | The user has no app:{id}:access. Step 2. |
| Signature verification fails | A pinned kid or a cached PEM. Always fetch https://admin.fixweb.cloud/.well-known/jwks.json; keys rotate. |
| Token accepted but roles look wrong | You are reading top-level claims. Everything is under properties. |
Which sign-in methods your users see (password, Google, Microsoft, …) is the operator's choice and needs no change on your side: Sign-in methods.
No human at the keyboard? Skip this flow and use a service token (admin-minted JWT, type: "service") instead of authorization code + PKCE.