Public API

/oidc.ashx · public API

Built-in OpenID Connect identity provider. The handler is fully spec-compliant for Authorization Code + PKCE, exposes discovery + JWKS at the conventional /.well-known paths, and signs id_token / access_token with RS256.

The userinfo endpoint is part of the OIDC spec but requires a Bearer token issued by this IdP, so it’s excluded here. Everything else below is callable without an existing CodeB session.
Two URL shapes, one handler. Every endpoint below is reachable in either form — the conventional /oauth2/v1/<name> path (used by most commercial OIDC providers and what discovery advertises), or the legacy /oidc.ashx?action=<name> form. RP libraries that follow discovery automatically use the /oauth2/v1/* shape and need no special configuration.

GET /.well-known/openid-configuration #

RFC 8414 / OpenID Connect Discovery 1.0 metadata document. Lists the issuer, endpoint URLs, supported response types, claims and scopes.

Request

No parameters.

Response

Standard JSON document, e.g.:

{
  "issuer": "https://phone.codeb.io",
  "authorization_endpoint": "https://phone.codeb.io/oidc.ashx?action=authorize",
  "token_endpoint": "https://phone.codeb.io/oidc.ashx?action=token",
  "userinfo_endpoint": "https://phone.codeb.io/oidc.ashx?action=userinfo",
  "jwks_uri": "https://phone.codeb.io/.well-known/jwks.json",
  "end_session_endpoint": "https://phone.codeb.io/oidc.ashx?action=end_session",
  "revocation_endpoint": "https://phone.codeb.io/oidc.ashx?action=revoke",
  "scopes_supported": ["openid","profile","email","groups"],
  "response_types_supported": ["code"],
  "code_challenge_methods_supported": ["S256"],
  "id_token_signing_alg_values_supported": ["RS256"]
}

Example

curl https://phone.codeb.io/.well-known/openid-configuration
Also reachable as /oidc.ashx?action=discovery.

GET /.well-known/jwks.json #

RFC 7517 JSON Web Key Set. Contains the RSA public key used to verify RS256-signed id_token / access_token JWTs issued by this IdP.

Request

No parameters.

Response

{
  "keys": [
    { "kty":"RSA","use":"sig","alg":"RS256",
      "kid":"<current-kid>","n":"<modulus-b64u>","e":"AQAB" }
  ]
}

Example

curl https://phone.codeb.io/.well-known/jwks.json
Includes both the active key and any rotation-window predecessor so old tokens still verify until they expire. Cache for at most 24 h.

GET /oidc.ashx?action=authorize #

Authorization Code flow entry point with PKCE. Public clients (browsers, native apps) must use code_challenge + code_challenge_method=S256.

Request

Query parameters: response_type=code, client_id, redirect_uri (byte-for-byte registered), scope (default openid), state, nonce, code_challenge, code_challenge_method=S256. Optional fast-path: cp_v2_assertion=<jwt> issued by an already-signed-in same-origin session.

Response

302 redirect to redirect_uri?code=…&state=… on success, or to /login.html?return=… if the visitor isn't signed in yet.

Errors

400 with JSON {error, error_description} on unknown client, invalid redirect URI, missing PKCE, or unsupported challenge method.

Authorization codes are single-use and live 60 seconds.

POST /oidc.ashx?action=login #

Form POST that authenticates the visitor using the same HA1 (MD5(user:realm:password)) as the SIP credentials store. Computes HA1 client-side so plaintext passwords never reach the IdP. When the return URL points back to ?action=authorize, the code is minted directly — no cookie is set.

Request

Body fields: user, ha1 (32 hex), return (optional URL).

Response

Either a 302 redirect with ?code=… appended to return, or JSON { ok: true, code: "…" }.

Errors

400 / 401 { error: "invalid_credentials" }. 429 if IP exceeded 10 attempts in the last 60 s.

HA1 comparison is constant-time. The login is stateless: no session cookie is set on the IdP origin.

POST /oidc.ashx?action=token #

RFC 6749 token endpoint. Exchanges either an authorization code (with PKCE verifier) or a refresh token for a fresh id_token, access_token and rotated refresh_token.

Request

Form / JSON body: grant_type (authorization_code or refresh_token), code, redirect_uri, code_verifier, client_id, client_secret (confidential clients only), refresh_token.

Response

{
  "id_token": "<rs256-jwt>",
  "access_token": "<rs256-jwt>",
  "refresh_token": "<opaque>",
  "expires_in": 3600,
  "token_type": "Bearer"
}

Errors

400 { error: "invalid_grant" } on code reuse, PKCE mismatch, expired code, unknown client. 401 on confidential-client secret mismatch.

Access tokens last 1 hour. Refresh tokens last 4 hours and rotate on every use.

GET /oidc.ashx?action=end_session #

OpenID Connect RP-Initiated Logout 1.0. Clears the IdP-side SSO assertion and bounces the browser back to post_logout_redirect_uri if it’s registered for the client.

Request

Optional query: id_token_hint, post_logout_redirect_uri, state.

Response

302 to either the registered post-logout URI or /login.html.

Errors

400 if post_logout_redirect_uri isn’t in the client’s registered allow-list.

POST /oidc.ashx?action=revoke #

RFC 7009 token revocation. Useful when a user logs out of a confidential RP and you want to invalidate the refresh token immediately.

Request

Body: token, optional token_type_hint=access_token|refresh_token, client_id, client_secret (confidential clients).

Response

200 { "ok": true } — per the RFC, succeeds even if the token is already invalid.

Errors

400 on unknown / mis-authenticated client.

POST /oauth2/v1/introspect #

RFC 7662 token introspection. Submit any token issued by this IdP — access_token, id_token, or refresh_token — and find out whether it’s still active, who it belongs to, and when it expires.

Request

Form / JSON body: token (required), token_type_hint (optional — access_token, id_token or refresh_token), client_id (required only when introspecting a token that was issued to a confidential client), client_secret (then required).

Response

For an active token (RFC 7662 §2.2):

{
  "active": true,
  "token_type": "Bearer",
  "client_id": "<client>",
  "sub": "<user>",
  "scope": "openid profile email",
  "iss": "https://phone.codeb.io",
  "aud": "<client>",
  "exp": 1717248000,
  "iat": 1717244400
}

For an inactive / unknown / expired token — per RFC 7662 §2.2 the only field returned is active:

{ "active": false }

Errors

400 if token is missing. 401 if the named confidential client’s secret fails to verify. Never a 4xx for “token unknown” — that returns 200 {active: false} by spec.

Useful for resource servers that want to defer token-validation logic to the IdP instead of verifying JWT signatures themselves. Note: for high-traffic resource servers, local JWT verification using the JWKS is usually faster.

GET /oidc.ashx?action=ping #

Build stamp + tenant identity. Handy as a liveness probe.

Request

No params.

Response

{ "ok": true, "build": "...", "tenant": "phone.codeb.io", "now": 1717248000 }

Example

curl https://phone.codeb.io/oidc.ashx?action=ping
Need an admin endpoint? Admin-only and OIDC Bearer-gated routes are documented inside the admin UI itself (visible only to signed-in admins on this host). The public API set on this page is the surface you can integrate against without provisioning a CodeB user.

Questions? Ask us · Index: All public APIs