OpenID Connect and OAuth 2.1
Connect apps to IdRa's authorization server with OIDC and OAuth 2.1: client types, tokens, claims, discovery and custom APIs.
IdRa is an OpenID Connect provider. Each IdRa organization has one issuer:
https://<your IdRa address>/api/auth| Endpoint | Path |
|---|---|
| Discovery | /api/auth/.well-known/openid-configuration |
| OAuth metadata (RFC 8414) | /.well-known/oauth-authorization-server/api/auth |
| Authorize | /api/auth/oauth2/authorize |
| Token | /api/auth/oauth2/token |
| UserInfo | /api/auth/oauth2/userinfo |
| JWKS | /api/auth/jwks |
| Introspection | /api/auth/oauth2/introspect |
| Device authorization | /api/auth/device/code (users approve at /device) |
Most libraries only need the issuer: they read the rest from discovery.
Create an OIDC app
Applications → Create App Integration → OIDC - OpenID Connect, then pick the application type:
| Type | Client | Grants |
|---|---|---|
| Web Application | Confidential (client secret) | Authorization code (+ PKCE), refresh token |
| Single-Page Application | Public, PKCE required | Authorization code, refresh token |
| Native Application | Public, PKCE required, no secret | Authorization code, refresh token |
| API Services | Confidential | Client credentials only |
Single-page apps on another origin can call the token, userinfo, revoke, introspect, JWKS and discovery endpoints: they answer CORS requests from any origin, without cookies.
Native apps redirect to a private-use scheme (com.example.app:/callback), to http on 127.0.0.1, [::1] or localhost, or to https on a public host. Web and single-page apps need https on a public host. javascript:, data: and plain http on other hosts are refused for all of them.
Enter the App integration name, the Sign-in redirect URIs (one per line, exact match) and optionally an Initiate login URI (where the My Apps tile points). The client secret is shown once; Generate new secret on the Sign On tab replaces it.
The Sign On tab shows the Client ID, issuer and discovery URL, and lets you change:
- Grant types: Authorization Code, Refresh Token, Client Credentials, Device Authorization.
- Client authentication: HTTP Basic (
client_secret_basic), request body (client_secret_post) or Private key JWT (private_key_jwt, see below). - Sign-in redirect URIs, Sign-out redirect URIs and a Back-channel logout URI (https).
- Client credentials scopes, Require user consent (off for new apps) and Require PKCE as additional verification (on by default; always on for SPAs and native apps).
- Require DPoP-bound tokens: see below.
Then assign the app to people or groups.
Private key JWT
Instead of a secret, the app signs a short-lived JWT with its private key, and IdRa checks it against the public keys you give it. On the Sign On tab, pick Private key JWT, then either paste a JWKS or enter a JWKS URL (https). IdRa reads the URL when you save, every 5 minutes as assertions arrive, and within 30 seconds of an assertion naming a new kid. If the URL stays unreachable for 10 minutes, the app can't authenticate until it's back.
Send client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer and client_assertion to the token endpoint. The JWT needs iss and sub set to the client ID, aud set to the token endpoint or the issuer, a unique jti (each one works once) and an exp at most 5 minutes away.
The app's old client secret stops working when you switch. Switching back issues a new secret, shown once.
DPoP
With Require DPoP-bound tokens on, the token endpoint refuses requests without a DPoP proof, and tokens are bound to the proof's key: token_type is DPoP, and using or refreshing a token needs a proof from that same key. Apps that send a proof without this setting get bound tokens too.
Access after sign-in
Refresh tokens and approved device codes are checked again each time they're used: the app's assignment, blocked zones, ThreatInsight, the Global Session Policy, the app's sign-on policy and the API access policies of its resources. A denial returns an error and is logged as app.access; the token isn't consumed, so it works again if access is restored.
Nobody is present at a refresh to answer a prompt, so:
- A rule that asks for stronger assurance doesn't block a refresh: that was settled when the grant was issued.
- The session lifetime doesn't end a grant. Refresh tokens have their own lifetime.
- Network zones see whoever calls the token endpoint. For a web app, that's the app's server, not the person's network, so an "allow only from this zone" rule also has to cover that server.
- Device conditions see the session's device while that session lives, and no device after it ends.
A device code's API access rules run at the token request, when there's a user to evaluate them for.
Tokens and claims
- PKCE uses
S256only. Implicit and password grants are refused. - Tokens are signed with RS256; keys are published at the JWKS endpoint and rotate under Settings → Keys (old tokens stay valid until they expire).
- Scopes:
openid,profile,email,offline_access(refresh tokens),groups, plus custom scopes from Security → API. groupsadds agroupsclaim (group names) to the ID token, UserInfo and access token.profileaddsname,preferred_username(the email) andupdated_at.- When a person is deactivated or signed out everywhere, refresh tokens are revoked and apps with a back-channel logout URI receive a logout token. Issued JWT access tokens stay valid until they expire.
Example: generic OIDC client
// any OIDC library; values from the app's Sign On tab
const config = {
issuer: 'https://idra.example.com/api/auth',
clientId: '<client id>',
clientSecret: '<client secret>',
redirectUri: 'https://app.example.com/callback',
scope: 'openid profile email groups',
};Custom APIs (authorization servers)
Security → API defines authorization servers for your own APIs: an audience, scopes, static claims and access policies that decide which clients and groups may get which scopes. The token preview shows what a given client and user would receive. All authorization servers share the issuer above; the API is told apart by the token's aud.