JumpCloud Integration
JumpCloud is a standard OIDC identity provider and SCIM 2.0 directory. AxonFlow uses it for per-user fleet identity: each developer authenticates with a JumpCloud-issued OIDC token, and their role is resolved from the SCIM-synced directory rather than from any claim inside the token.
This gives a fleet two things a single shared credential cannot:
- Attribution - every governed action is tied to the individual developer's validated identity.
- Authorization - the developer's role comes from the directory AxonFlow audits, so an IdP misconfiguration cannot mint an administrator.
JumpCloud is first-classed as an OIDC provider (provider: "jumpcloud"). It uses
the same verifier inputs - issuer, audience, JWKS URI - as the generic oidc
provider; selecting JumpCloud simply pre-fills its well-known endpoints.
How the Two Halves Fit Together
| Concern | Source | Mechanism |
|---|---|---|
| Who the user is (identity) | The JumpCloud OIDC token | Validated against JumpCloud's JWKS (issuer, audience, expiry, RS256 signature) |
| What the user can do (role) | The SCIM-synced directory | Group-to-role mapping, never a token claim |
Configure SCIM first so the directory is populated before any token resolves to more than least privilege.
Both halves above are the fleet / governed-request plane (plane b): they decide who a developer is and what they can do when their tools call the platform. There is a separate, optional third concern - signing a human into the customer portal UI in a browser (plane a), covered in Part 3.
AxonFlow stores a single SSO configuration per tenant, and it is either SAML or
OIDC. Part 2 above sets that configuration to OIDC for fleet identity. So on a
tenant that uses per-user fleet tokens, browser portal login must also be OIDC:
you extend the same OIDC configuration with portal client credentials, and it then
serves both fleet token verification (via the audience) and browser login (via the
client id and secret). SAML portal login uses a saml configuration that would
replace the OIDC one and disable fleet identity, so SAML portal login is only
for a JumpCloud deployment that does not use per-user fleet tokens. SCIM (Part
- is a separate system and works with either.
Portal login is optional - the portal always accepts an organization password - so set up Part 3 only if you want your team to reach the portal through JumpCloud.
Before You Configure JumpCloud
Have these ready:
- JumpCloud admin access
- an AxonFlow SCIM token created from the customer portal
- the real enterprise portal hostname for the tenant you are provisioning into
- an operator with the
sso:configurepermission for the OIDC and role-mapping steps
Part 1 - SCIM Provisioning
Step 1: Create the AxonFlow SCIM token
In the customer portal, go to Settings → SCIM → Create Token and copy the token once. It is not shown again. Your SCIM base URL looks like this:
https://YOUR_PORTAL_OR_ENTERPRISE_DOMAIN/scim/v2
Step 2: Add JumpCloud SCIM/directory sync
-
In the JumpCloud Admin Console, open the application you use for AxonFlow (or create one) and enable Identity Management.
-
Point the SCIM connector at
https://YOUR_PORTAL_OR_ENTERPRISE_DOMAIN/scim/v2. -
For authentication, use a header with the full bearer-token format:
Bearer scim_your_token_hereThat matches the SCIM middleware, which expects an
Authorizationheader with theBearerscheme.
Step 3: Assign a pilot group
Do not begin with a company-wide assignment. Assign one pilot developer group so users and groups sync, then verify:
- the users appear in the right tenant
- the identity shape is correct
- update and deactivation flows behave correctly
Step 4: Map JumpCloud groups to roles
Roles come from the directory, never from the token. Map each synced JumpCloud
group to an AxonFlow role using the group-to-role mapping endpoints (portal
session, gated by sso:configure):
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/v1/scim/roles | List assignable role IDs |
| GET | /api/v1/scim/groups/role-mappings | List current group-to-role mappings |
| PUT | /api/v1/scim/groups/{id}/role-mapping | Set or clear a mapping for one synced group |
The fleet resolver keys on the role name, so map groups to the seeded system
roles (admin, owner, policy_admin, developer, member, viewer).
Mapping a group to a differently-named custom role resolves to least privilege.
See Group to Role Mapping for rollout order and naming guidance.
Part 2 - OIDC SSO (Per-User Fleet Identity)
Step 5: Create the OIDC application in JumpCloud
- JumpCloud Admin Console → SSO Applications → Add New Application → Custom OIDC App.
- Grant type: Authorization Code (add Refresh Token as desired). Set the redirect URI to your token-delivery tooling (a device-flow or CLI helper).
- Note the values you will need in AxonFlow:
- Issuer:
https://oauth.id.jumpcloud.com/ - JWKS URI:
https://oauth.id.jumpcloud.com/.well-known/jwks.json - Audience: your app's client ID (or a custom audience you configure)
- Issuer:
- Ensure the
emailclaim is included by requesting the standardopenid emailscopes. - Assign the app to the same developer group(s) you synced via SCIM.
Confirm the issuer, JWKS URI, and scopes against your tenant's discovery
document at https://oauth.id.jumpcloud.com/.well-known/openid-configuration
rather than copying them. A mismatched iss or aud is rejected, which looks
identical to "tokens don't work".
Step 6: Configure the OIDC provider in AxonFlow
Create the SSO configuration (portal session, gated by sso:configure):
curl -X POST "$PORTAL_URL/api/v1/sso/config" \
-H "Cookie: <portal session>" \
-H "Content-Type: application/json" \
-d '{
"provider": "jumpcloud",
"enabled": true,
"oidc_issuer": "https://oauth.id.jumpcloud.com/",
"oidc_audience": "<your client id>",
"oidc_jwks_uri": "https://oauth.id.jumpcloud.com/.well-known/jwks.json",
"oidc_claim_mapping": {"email": "email"}
}'
POSTcreates and returns409if a config already exists. To change an existing config, usePUT /api/v1/sso/configwith the same body.- Issuer and JWKS URI must use HTTPS. URLs that resolve to private or
cloud-metadata endpoints (
169.254.169.254, RFC-1918 hosts,*.internal) are rejected, because AxonFlow fetches these server-side. - Use a per-tenant issuer or audience. The verifier trusts the identity in a token signed by the configured issuer and audience. If two tenants configure the same issuer and audience, a token minted for one is structurally valid for the other. Give each tenant a distinct OIDC app so a token cannot cross a tenant boundary.
oidc_claim_mapping.emailnames the claim carrying the developer identity (defaultemail; some IdPs usepreferred_username).
You can retrieve JumpCloud's pre-filled defaults from
GET /api/v1/sso/providers/defaults?provider=jumpcloud.
Part 3 - Portal Login (SAML or OIDC, optional)
Set this up only if you want people to sign into the customer portal UI through JumpCloud in a browser. The portal always accepts an organization password as a fallback.
The protocol you can use is constrained by the single-SSO-configuration rule above:
- If this tenant uses fleet OIDC (Part 2), which is the usual JumpCloud case, use OIDC portal login. You extend the Part 2 configuration with portal client credentials, so fleet token verification keeps working. Skip to OIDC portal login. Requires v9.16.0 or later.
- Only if this tenant does NOT use fleet OIDC (no Part 2) may you use SAML portal login (Steps 7 to 10). SAML sets the tenant's configuration to
saml; do not run it on a tenant that relies on fleet OIDC, because it replaces that OIDC configuration and disables fleet identity. Requires v9.15.0 or later.
Both protocols create the same portal session and resolve roles the same way (from SCIM).
Step 7: Set SSO_BASE_URL
On a self-hosted deployment, set SSO_BASE_URL to the portal's external URL (for
example https://portal.yourcompany.com) and restart. The SAML reply address is
derived from it; if it is unset, the identity provider posts the login response
to the wrong host and login fails. The portal logs a warning at startup when this
is the case.
Step 8: Create a SAML application in JumpCloud
In JumpCloud, add a new SSO application of type SAML (a Custom SAML app is fine). Use these steps only on a tenant that does not run fleet OIDC (Part 2), since the SAML configuration replaces the tenant's OIDC one. Set:
- ACS URL / SP Reply URL:
https://<your SSO_BASE_URL host>/auth/saml/<sso-tenant>/callback, where<sso-tenant>is__platform__on in-vpc deployments and your org id on SaaS. - SP Entity ID: use the value from
GET /api/v1/sso/sp-metadata(it is derived fromSSO_BASE_URL). - Email attribute: map the user's email to an attribute named
email(the portal reads the email from the assertion). - Group attribute (optional): include the user's groups if you want portal role auto-provisioning in Step 10.
GET /api/v1/sso/sp-metadata on your deployment returns the exact entity ID and
ACS URL to paste, so you do not have to hand-build them.
Step 9: Configure the SAML provider in AxonFlow
From the customer portal, signed in as an operator with sso:configure, open SSO
settings and add a SAML provider. Point it at your JumpCloud SAML app's IdP
metadata URL (or paste the IdP certificate and SSO URL); POST /api/v1/sso/fetch-metadata
will pull and validate the metadata for you. Confirm the email attribute mapping,
then enable SSO. Use the built-in test flow before rolling it out.
Step 10: Roles for SAML-logged-in users
Two options, and they compose:
- SCIM (recommended, from Part 1): the group-to-role mapping you already configured applies to SAML-logged-in users too, and it reconciles on every sync (add and remove).
- Auto-provision on login: if you enable "Auto-provision users" on the SAML config, a first-time SSO user with no existing role is assigned the role mapped from their group (or the default role) on login. It only ever adds a role when the user has none, and it does not de-provision - SCIM owns the full lifecycle.
OIDC portal login (recommended for a fleet tenant, v9.16.0)
On a tenant that already has the Part 2 OIDC configuration, you add browser portal login by extending that same configuration with portal client credentials. In JumpCloud, create a Custom OIDC app for the portal with grant type Authorization Code and register the redirect URI:
https://<your SSO_BASE_URL host>/auth/oidc/<sso-tenant>/callback
where <sso-tenant> is __platform__ on in-vpc deployments and your org id on
SaaS. You can use a dedicated portal app (its own client id) or reuse the Part 2
app; either way the configuration keeps its fleet audience and gains the portal
client id and secret, which are separate fields. Because Part 2 already created
the configuration row, update it with PUT (a fresh POST returns 409):
curl -X PUT "$PORTAL_URL/api/v1/sso/config" \
-H "Cookie: <portal session>" \
-H "Content-Type: application/json" \
-d '{
"provider": "jumpcloud",
"enabled": true,
"oidc_issuer": "https://oauth.id.jumpcloud.com/",
"oidc_audience": "<your fleet token audience, from Part 2>",
"oidc_jwks_uri": "https://oauth.id.jumpcloud.com/.well-known/jwks.json",
"oidc_client_id": "<your portal app client id>",
"oidc_client_secret": "<your portal app client secret>",
"oidc_claim_mapping": {"email": "email"}
}'
The client secret is stored with the same at-rest posture as a SAML private key
(never returned, never logged), and GET /api/v1/sso/config returns the exact
oidc_redirect_uri to register. Fleet token verification (Part 2) keeps using
oidc_audience; portal login uses the client credentials, so one OIDC
configuration serves both planes. Role auto-provisioning works the same way as it
does for SAML. See SSO Configuration
for the full field reference and the AXONFLOW_OIDC_ALLOW_PRIVATE note for
internal identity providers.
Recommended Rollout Pattern
- Configure SCIM and validate provisioning with a pilot group.
- Map the pilot group to a non-privileged role (for example
developer). - Create the JumpCloud OIDC app and configure the provider in AxonFlow.
- Validate one developer's end-to-end login: token validates, role resolves.
- Expand group assignment and role mapping gradually.
Common Issues
Every token is rejected
Check that the configured oidc_issuer and oidc_audience exactly match what
JumpCloud emits (including any trailing slash on the issuer). Confirm the JWKS
URI is reachable over HTTPS and the token is RS256-signed.
Login succeeds but the developer can read nothing
The SCIM directory is not populated, or the developer's group is not mapped to a role. Provision the group first, then map it - an unmapped identity resolves to least privilege by design.
sso:configure denied
The OIDC configuration and group-to-role mapping endpoints are privilege grants,
so they require the sso:configure permission and are deliberately not reachable
with a SCIM directory-sync token.