OIDC Integration
jitsudo uses OpenID Connect (OIDC) for all authentication. The CLI authenticates users via the Device Authorization Flow (RFC 8628) and the server validates JWTs issued by your IdP.
How Authentication Works
Section titled “How Authentication Works”- CLI → IdP:
jitsudo loginstarts the device flow, directing the user to authenticate in any browser. - IdP → CLI: After browser authentication, the IdP issues an ID token (JWT).
- CLI → Server: Every API request carries the ID token as a
Bearertoken in theAuthorizationheader. - Server → IdP: jitsudod validates the token by fetching the IdP’s JWKS from
{oidc_issuer}/.well-known/openid-configurationand verifying the JWT signature, issuer (iss), audience (aud), and expiry (exp).
Server Configuration
Section titled “Server Configuration”auth: # Must match the `iss` claim in tokens issued by your IdP. oidc_issuer: "https://your-idp.example.com"
# OIDC client ID registered with your IdP for the jitsudo server. client_id: "jitsudo-server"You need two OIDC clients registered with your IdP:
jitsudo-server— the server’s resource server / audiencejitsudo-cli— the CLI’s public client (uses device flow, hardcoded in the CLI)
Required Scopes
Section titled “Required Scopes”The CLI requests these scopes:
| Scope | Purpose |
|---|---|
openid | Required for OIDC |
email | Used as the user’s identity in requests and audit log |
profile | Display name |
groups | Group membership (used in eligibility/approval policies) |
offline_access | Refresh token (for future silent refresh support) |
Make sure your IdP includes the groups claim in the ID token.
Step 1: Create a Server Application
Section titled “Step 1: Create a Server Application”- In Okta Admin Console: Applications → Create App Integration → OIDC → Web Application.
- Set Grant type: Device Authorization.
- Note the Client ID (
jitsudo-server) — this is yourclient_id. - Set Issuer to your Okta org URL:
https://your-org.okta.com.
Step 2: Create a CLI Application
Section titled “Step 2: Create a CLI Application”- Applications → Create App Integration → OIDC → Native Application.
- Set Grant type: Device Authorization.
- Set Client ID to
jitsudo-cli(or note the generated one and configure it in the CLI source if needed).
Step 3: Add Groups Claim
Section titled “Step 3: Add Groups Claim”In the Sign-On tab of the server app, edit the token settings:
- Add a claim: Name
groups, Include inID Token, Value typeGroups, FilterMatches regex: .*.
Step 4: Configure jitsudod
Section titled “Step 4: Configure jitsudod”auth: oidc_issuer: "https://your-org.okta.com" client_id: "jitsudo-server"Step 5: Log In
Section titled “Step 5: Log In”jitsudo login --provider https://your-org.okta.comMicrosoft Entra ID (Azure AD)
Section titled “Microsoft Entra ID (Azure AD)”Step 1: Register the Server Application
Section titled “Step 1: Register the Server Application”az ad app create \ --display-name "jitsudo-server" \ --identifier-uris "api://jitsudo-server"
# Note the appId — this is your client_idaz ad app show --display-name "jitsudo-server" --query appId -o tsvEnable device flow on the registration:
# In Azure Portal: App registrations → your app → Authentication# Add platform: Mobile and desktop applications# Enable "Allow public client flows"Step 2: Add Groups Claim
Section titled “Step 2: Add Groups Claim”- App registrations → your app → Token configuration → Add groups claim.
- Select Security groups and include in ID Token.
Step 3: Register the CLI Application
Section titled “Step 3: Register the CLI Application”az ad app create --display-name "jitsudo-cli"# Enable device flow and "Allow public client flows"# The appId becomes the CLI's client ID (must match "jitsudo-cli" constant in source)Step 4: Configure jitsudod
Section titled “Step 4: Configure jitsudod”auth: oidc_issuer: "https://login.microsoftonline.com/<TENANT_ID>/v2.0" client_id: "<SERVER_APP_CLIENT_ID>"Step 5: Log In
Section titled “Step 5: Log In”jitsudo login --provider "https://login.microsoftonline.com/<TENANT_ID>/v2.0"Keycloak
Section titled “Keycloak”Step 1: Create a Realm and Clients
Section titled “Step 1: Create a Realm and Clients”- In Keycloak Admin Console, create a realm (e.g.
jitsudo). - Create a client: Clients → Create → Client ID:
jitsudo-server.- Protocol:
openid-connect - Access Type:
confidential(orpublicfor development) - Enable Device Authorization Grant.
- Protocol:
- Create a client: Client ID:
jitsudo-cli.- Protocol:
openid-connect - Access Type:
public - Enable Device Authorization Grant.
- Protocol:
Step 2: Add Groups Mapper
Section titled “Step 2: Add Groups Mapper”For each client, add a mapper:
- Mapper type: Group Membership
- Token Claim Name:
groups - Add to ID token: ON
Step 3: Configure jitsudod
Section titled “Step 3: Configure jitsudod”auth: oidc_issuer: "https://keycloak.example.com/realms/jitsudo" client_id: "jitsudo-server"Step 4: Log In
Section titled “Step 4: Log In”jitsudo login --provider https://keycloak.example.com/realms/jitsudoGoogle Workspace
Section titled “Google Workspace”Step 1: Create OAuth Clients
Section titled “Step 1: Create OAuth Clients”In Google Cloud Console:
- APIs & Services → Credentials → Create Credentials → OAuth client ID.
- Application type: Desktop app (supports device flow via workaround).
- Create one for the server (
jitsudo-server) and one for the CLI (jitsudo-cli).
Dex as a Bridge
Section titled “Dex as a Bridge”Dex federates to Google Workspace and provides standard RFC 8628 device flow:
connectors: - type: google id: google name: Google config: clientID: <GOOGLE_CLIENT_ID> clientSecret: <GOOGLE_CLIENT_SECRET> redirectURI: https://dex.example.com/callback hostedDomains: - your-org.comauth: oidc_issuer: "https://dex.example.com" client_id: "jitsudo-server"Troubleshooting
Section titled “Troubleshooting”Token validation fails with iss mismatch
Section titled “Token validation fails with iss mismatch”The oidc_issuer in your config must exactly match the iss claim in the JWT. Fetch a token and inspect it:
# Decode the JWT (base64 decode the middle segment)jitsudo login --provider https://your-idp.example.comcat ~/.jitsudo/credentials | python3 -c "import json, base64, systoken = json.load(sys.stdin)['Token']payload = token.split('.')[1]# Add paddingpayload += '=' * (4 - len(payload) % 4)print(json.dumps(json.loads(base64.b64decode(payload)), indent=2))"Check the iss field and make sure it matches your config exactly.
groups claim missing
Section titled “groups claim missing”If eligibility policies use input.user.groups but the claim is empty, your IdP is not including groups in the ID token. Add the groups claim as described above for your IdP.
Device flow not supported
Section titled “Device flow not supported”Not all IdPs enable device flow by default. Check that:
- The client type is
NativeorPublic(notWeb). - Device authorization grant is explicitly enabled.
- Your IdP’s device authorization endpoint is reachable from the CLI machine.