Module 5 — Server-side & Management API
Learning objectives
- Use the Client Credentials grant for machine-to-machine (no user) calls.
- Configure
@faable/auth-sdkto read/mutate users, clients, connections.- Explain audience and scopes for management tokens.
- Know what Actions and webhooks are for.
When there’s no user: Client Credentials
A backend job — sync users, provision a tenant, react to an event — has no logged-in user. It authenticates as itself with a confidential client using the Client Credentials grant. Reference: Client Credentials Flow.
You get an access token (no ID token, no refresh token — there’s no user to
represent). The token’s aud and scope decide what it can do.
Calling the Management API with @faable/auth-sdk
The Management API is the admin surface of your tenant: CRUD for users, clients, connections, teams, etc. The server SDK handles auth for you, Octokit-style — you give it a strategy and credentials, no environment magic:
import { FaableAuthApi, authClientCredentials } from '@faable/auth-sdk'
const api = FaableAuthApi.create({
authStrategy: authClientCredentials,
auth: {
client_id: process.env.FAABLEAUTH_CLIENT_ID!,
client_secret: process.env.FAABLEAUTH_CLIENT_SECRET!
},
domain: process.env.FAABLEAUTH_DOMAIN! // your tenant, e.g. acme.auth.faable.link
})
const { results } = await api.listUsers().first()
await api.updateUser(userId, { locale: 'es' })You supply domain + credentials, and allow the client its Management API
scopes once in the dashboard (below). The SDK discovers the right management
audience from the domain automatically (it reads the tenant’s
/.well-known/openid-configuration).
Audience & scopes (the two things that gate a management token)
See APIs and the Client Credentials Flow for the full reference. The short version:
- Audience (
aud) — which API the token is for. The management audience isfaable:management:<account_id>. A token for the wrong audience is rejected (aud_mismatch). The SDK sets this for you via discovery. - Scopes / permissions — what the token may do, as
verb:resourcestrings:read:users,update:users,read:clients, … A call needs the matching scope.
Which scopes does the token get? The client’s allow-list
Every client has a list of Management API scopes (management_scopes): what a
client_credentials token for the management audience may carry. It is set per
client — dashboard → your tenant → Clients → the client → OAuth tab →
Management API scopes, or management_scopes on POST /client/:id.
- Request no scopes (what the SDK does by default) → you get the whole allow-list, never more.
- Request some → you get those that are on the list; the rest are dropped.
- The list is empty → the request is refused:
403 access_deniedwitherror_code: management_scopes_empty. New clients start empty, so a client that only signs users in can’t administer your tenant with its secret. - None of what you requested is on the list →
400 invalid_scope(error_code: management_scope_not_allowed).
So the common case — “I made a client for my backend, put the id/secret in the SDK” —
needs one more step: tick the scopes that backend uses (least privilege), e.g. only
read:users for a reporting job. You can pick them when you create the client
(Management API access) or later on its page. See
Calling the Faable Management API
for the full rules.
Extending the flow: Actions
Actions run your JavaScript inside the auth flow at
hooks like postLogin. Use them to enforce rules (block a login, add custom claims)
or to pause the flow and send the user to your own UX.
Canonical example — progressive profiling: a social provider didn’t return a
required field (classic: GitHub with a private email). A postLogin Action can call
api.redirect.sendUserTo(url) to pause the flow, you collect the missing data in your
own page, then resume at /continue. To guarantee the data is really there, the
continue hook should api.access.deny(reason) if the field is still empty — otherwise
a user could close the tab and replay to log in with an incomplete profile.
You don’t need to write Actions to pass this course, but you must know what they’re for and the progressive-profiling pattern.
Reacting to changes: Webhooks
Webhooks are signed HTTPS callbacks Faable sends on
events like user.created, user.updated, user.deleted, auth.login. Use them to
keep your own systems in sync. Always verify the signature before trusting a
payload.
Check yourself
- A nightly job updates user locales. Which grant and which SDK?
- You create an M2M client, leave its Management API scopes empty and request no scopes. Can it read users?
- Your M2M call returns
aud_mismatch. What’s wrong, and does the SDK normally prevent this? - GitHub login succeeds but the user has no email. Which feature do you reach for?
Answers
- Client Credentials grant via
@faable/auth-sdk(server-side). - No — with an empty allow-list the token request is refused
(
403 management_scopes_empty). Allowread:usersunder Management API scopes on the client and the same request (no scopes) then gets exactlyread:users. - The token’s audience isn’t the tenant’s
faable:management:<account_id>. The SDK auto-discovers the correct audience fromdomain, so this usually means a misconfigureddomainor a hand-rolled token bypassing the SDK. - An Action (
postLogin) for progressive profiling — pause the flow, collect the email, resume, anddenyif still missing.
You’ve finished the modules. Now do the Hands-on Lab, then take the Certification Exam.
Last updated on