Bondy Connect
Skip to content

OIDC HTTP API ​

The OIDC endpoints implement the OpenID Connect Authorization Code flow with PKCE. They are automatically registered when an API Gateway Specification includes an oidc security scheme.

Prerequisites ​

Before using the OIDC endpoints:

  1. Configure an OIDC provider in the realm's info.oidc_providers (see OIDC Authentication).
  2. Include "oidcrp" and "cookie" in the realm's authmethods.
  3. Load an API Gateway Specification with an oidc security scheme.

API ​

The following endpoints are registered under the API version's base_path:

NameMethodURL
LoginGET<base_path>/oidc/login
CallbackGET<base_path>/oidc/<provider>/callback
LogoutGET, POST<base_path>/oidc/logout
VerifyGET, HEAD<base_path>/oidc/verify, or the scheme's verify_path

<provider> is the value of the security scheme's provider key. The verify endpoint checks a Bondy credential for a reverse proxy, for example an NGINX auth_request. It answers 200 with the identity when the credential is valid, and 401 otherwise. See the HTTP API Gateway Specification.

The login, callback and logout endpoints support OPTIONS for CORS preflight. The Access-Control-Allow-Origin header is set to the request's Origin header value.

An error response from the login or callback endpoint has a JSON body. The body holds error, the error name that the examples below show. The body also holds the standard error payload. In that payload, uri is bondy.error.<error>, code is the error name, handle is S002 and nature is transient. The examples show only the error key. A method that an endpoint does not accept answers 405 with an empty body.

Login ​

Initiates the OIDC Authorization Code flow by redirecting the user to the Identity Provider's authorization endpoint.

Request ​

GET <base_path>/oidc/login

The route always uses the provider that the security scheme names in its provider key.

Query Parameters ​

ParameterTypeDefaultDescription
redirect_uristring"/"The SPA URL to redirect to after successful authentication
client_idstring"all"Scopes the Bondy ticket to a specific client application
device_idstring"all"Scopes the Bondy ticket to a specific device

Responses ​

Success — 302 Found ​

Redirects to the IdP's authorization endpoint with state, nonce, PKCE code_challenge, configured scopes, and the redirect_uri.

Errors ​

json
{
    "error": "unknown_provider"
}
json
{
    "error": "authorization_url_failed"
}
json
{
    "error": "provider_unavailable"
}

Example ​

bash
# Redirect user to login with the provider of the route's security scheme
# After authentication, redirect back to /app/dashboard
curl -v "https://api.example.com/v1.0/oidc/login?redirect_uri=/app/dashboard"

# Response:
# HTTP/2 302
# Location: https://login.microsoftonline.com/.../authorize?response_type=code&client_id=...&redirect_uri=...&state=...&nonce=...&code_challenge=...&scope=openid+profile+email

Callback ​

Receives the authorization callback from the IdP, exchanges the authorization code for tokens, issues a Bondy ticket, and redirects to the SPA.

WARNING

This endpoint is called by the IdP, not directly by the SPA. The redirect_uri configured in the OIDC provider has to point to this endpoint.

Request ​

GET <base_path>/oidc/<provider>/callback

Query Parameters (set by the IdP) ​

ParameterRequiredDescription
codeYesThe authorization code from the IdP
stateYesThe state token. It has to match the value generated during login.

Responses ​

Success — 302 Found ​

Sets two cookies and redirects to the SPA redirect_uri that was stored during the login step:

Response Headers:

HTTP/2 302
Location: /app/dashboard
Set-Cookie: bondy_ticket_com.example.myrealm=eyJhbG...; Path=/; Max-Age=2592000; SameSite=Lax; Secure; HttpOnly
Set-Cookie: bondy_csrf_com.example.myrealm=a1b2c3d4-...; Path=/; Max-Age=2592000; SameSite=Lax; Secure

Errors ​

json
{
    "error": "missing_code_or_state"
}
json
{
    "error": "invalid_state"
}
json
{
    "error": "state_expired"
}
json
{
    "error": "realm_mismatch"
}
json
{
    "error": "token_exchange_failed"
}
json
{
    "error": "missing_authid_claim"
}
json
{
    "error": "unknown_provider"
}
json
{
    "error": "provider_unavailable"
}
json
{
    "error": "ticket_issue_failed"
}

Logout ​

Revokes the Bondy ticket, clears cookies, and optionally performs RP-Initiated Logout at the IdP.

Request ​

GET <base_path>/oidc/logout
POST <base_path>/oidc/logout

Query Parameters ​

ParameterTypeDefaultDescription
realmstringRoute's realm_uriThe realm whose cookies should be cleared
redirect_uristring"/"Where to redirect after logout
cookie_domainstringFrom provider configOverride the cookie domain for clearing
cookie_same_sitestringFrom provider config, or laxOverride the SameSite attribute for clearing: none, lax or strict

Responses ​

Success — 302 Found ​

Always redirects. When the ticket names an OIDC provider and the IdP supports RP-Initiated Logout, the redirect goes to the IdP's end_session_endpoint. The redirect carries the ticket's ID token as id_token_hint when the ticket has one:

HTTP/2 302
Location: https://login.microsoftonline.com/.../logout?id_token_hint=eyJhbG...&post_logout_redirect_uri=/
Set-Cookie: bondy_ticket_com.example.myrealm=; Path=/; Max-Age=0; SameSite=Lax; Secure
Set-Cookie: bondy_csrf_com.example.myrealm=; Path=/; Max-Age=0; SameSite=Lax; Secure

Otherwise, redirects directly to redirect_uri.

Resilient Logout

The logout handler is designed to never crash. If the realm or OIDC provider no longer exists on this Bondy node, it will still clear the cookies and redirect. Ticket revocation is best-effort.

Example ​

bash
# Logout from the default realm, redirect to /login
curl -v "https://api.example.com/v1.0/oidc/logout?redirect_uri=/login"

# Logout from a specific realm
curl -v "https://api.example.com/v1.0/oidc/logout?realm=com.example.myrealm&redirect_uri=/login"

Ticket Claims ​

The Bondy ticket issued during the callback is a signed JWT with the following claims:

ClaimTypeDescription
idstringUnique ticket identifier (UUID v4)
authrealmstringThe realm URI
authidstringUser identity extracted from the IdP claims
authmethodstringAlways "oidcrp"
authroleslistRoles extracted from the IdP claims
issued_bystringSame as authid
issued_onstringBondy node name
issued_atintegerUnix timestamp (seconds)
expires_atintegerUnix timestamp (seconds)
scopeobject{"realm": "...", "client_id": "...", "device_id": "..."}
kidstringKey ID used for signing
oidc_providerstringProvider name
oidc_id_tokenstringRaw ID token JWT from the IdP (optional)
oidc_refresh_tokenstringRefresh token from the IdP (optional)
oidc_access_token_expires_inintegerAccess token expiry, as the IdP token response gives it (optional)