API reference

Identity API (OIDC)

Standards-based OpenID Connect on top of OAuth 2.0. Let business customers sign in to your application with their Credicorp account and read a verified identity. Discovery, JWKS and the PKCE authorization-code flow are fully conformant — any certified OIDC library works out of the box.

Credicorp is the OpenID Provider (OP); your application is a Relying Party (RP). Sign-in happens at sso.credicorp.co.uk, the token and userinfo endpoints sit on the public ring, and signing keys are published at the standard JWKS URL. Because the provider is conformant, you should not hand-roll the flow — use a certified client (we ship one in each SDK) and let it validate the ID token for you.

Issuer
https://sso.credicorp.co.uk
Discovery
/.well-known/openid-configuration
Flow
Authorization Code + PKCE (RFC 7636). Implicit flow is not supported.
ID token
JWT signed ES256; verify against the published JWKS.

Discovery

Everything an RP needs is advertised at the discovery document. Fetch it once at start-up and cache it; never hard-code endpoint URLs.

GEThttps://sso.credicorp.co.uk/.well-known/openid-configuration
json
{
  "issuer": "https://sso.credicorp.co.uk",
  "authorization_endpoint": "https://sso.credicorp.co.uk/authorize",
  "token_endpoint": "https://sso.credicorp.co.uk/token",
  "userinfo_endpoint": "https://sso.credicorp.co.uk/userinfo",
  "jwks_uri": "https://sso.credicorp.co.uk/.well-known/jwks.json",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "id_token_signing_alg_values_supported": ["ES256"],
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": ["openid", "profile", "email", "business", "accounts.read"]
}

Endpoints

MethodPathPurpose
GET/authorizeBegin sign-in; redirects the user to authenticate & consent.
POST/tokenExchange the authorization code (+ PKCE verifier) for tokens.
GET/userinfoReturn claims for the authenticated subject (bearer the access token).
GET/.well-known/jwks.jsonPublic keys for verifying ID-token signatures.
GET/.well-known/openid-configurationProvider metadata (discovery).

The PKCE authorization-code flow

Use Authorization Code with PKCE for every client type — web servers, SPAs and native apps alike. The four steps:

  1. Generate a random code_verifier and its SHA-256 code_challenge. Store the verifier in the session.
  2. Redirect the user to /authorize with the challenge and a unique state.
  3. Credicorp authenticates the user, they consent, and we redirect back to your redirect_uri with a one-time code.
  4. Your server POSTs the code + code_verifier to /token and receives an id_token, access_token and refresh_token.

Step 1 — Build the challenge

bash
# code_verifier: 43–128 chars of [A-Za-z0-9-._~]
verifier=$(openssl rand -base64 32 | tr -d '=+/' | cut -c -43)
challenge=$(printf "%s" "$verifier" | openssl dgst -sha256 -binary \
            | openssl base64 -A | tr '+/' '-_' | tr -d '=')

Step 2 — Redirect to /authorize

GET/authorize
url
https://sso.credicorp.co.uk/authorize
  ?response_type=code
  &client_id=rp_acme_live_2P
  &redirect_uri=https://app.acme.co.uk/auth/callback
  &scope=openid profile email business
  &state=x7Kp…
  &code_challenge=E9Melhoa2Ow…
  &code_challenge_method=S256

/authorize parameters

ParameterDescription
response_typereqAlways code.
client_idreqYour registered RP client id.
redirect_urireqMust exactly match a URI registered for the client.
scopereqSpace-delimited; must include openid.
statereqOpaque anti-CSRF value; echoed back on the callback.
code_challengereqBase64url SHA-256 of your verifier.
code_challenge_methodreqAlways S256.
nonceoptBound into the ID token to prevent replay.
promptoptlogin to force re-auth, none for silent SSO.

Step 3 & 4 — Exchange the code at /token

POST/token
bash
curl -s https://sso.credicorp.co.uk/token \
  -d "grant_type=authorization_code" \
  -d "code=ac_91Hb2…" \
  -d "redirect_uri=https://app.acme.co.uk/auth/callback" \
  -d "client_id=rp_acme_live_2P" \
  -d "code_verifier=$verifier"
javascript
import { Identity } from '@credicorp/sdk';

const oidc = await Identity.discover();          // reads discovery + JWKS
const client = new oidc.Client({
  client_id:    'rp_acme_live_2P',
  redirect_uri: 'https://app.acme.co.uk/auth/callback'
});

const tokens = await client.callback(req.query, {
  state:         req.session.state,
  code_verifier: req.session.verifier
});
// tokens.claims() → verified ID-token claims
php
use Credicorp\Identity;

$oidc   = Identity::discover();
$client = $oidc->client(
    clientId:    'rp_acme_live_2P',
    redirectUri: 'https://app.acme.co.uk/auth/callback',
);

$tokens = $client->callback($_GET, [
    'state'         => $_SESSION['state'],
    'code_verifier' => $_SESSION['verifier'],
]);

$claims = $tokens->claims();   // signature already verified

Token response 200 OK

json
{
  "token_type": "Bearer",
  "expires_in": 3600,
  "access_token": "at_8sV…",
  "refresh_token": "rt_K2p…",
  "id_token": "eyJhbGciOiJFUzI1NiIs…",
  "scope": "openid profile email business"
}

Always validate the ID token. Verify the ES256 signature against the JWKS, and check iss equals the issuer, aud equals your client_id, exp is in the future, and nonce matches what you sent. The SDK does all of this for you — do not parse the JWT yourself.

Scopes & claims

Request the minimum scope you need. Identity claims are returned in the ID token and, in full, from /userinfo.

ScopeGrants
openidRequired. Returns sub — the stable subject identifier.
profilename, given_name, family_name, updated_at.
emailemail and email_verified.
businessVerified company identity: company_number, company_name, company_role.
accounts.readLets the access token call the Accounts API on the user's behalf.

/userinfo response

json
curl https://sso.credicorp.co.uk/userinfo -H "Authorization: Bearer at_8sV…"

{
  "sub": "usr_2WdR7yK",
  "name": "Priya Anand",
  "email": "priya@acme.co.uk",
  "email_verified": true,
  "company_number": "09876543",
  "company_name": "Acme Trading Ltd",
  "company_role": "director"
}

Key the user on sub, not email. A person's email can change; sub is the permanent, opaque identifier for that Credicorp account and is what you should store against your own user record.

Refreshing & sign-out

Access tokens live for one hour. Exchange the refresh token at /token with grant_type=refresh_token to obtain a fresh access token without re-prompting. To end a session, clear your own cookie and redirect the user to the end-session endpoint advertised in discovery. Refresh tokens rotate on use — always persist the newest one returned.

errorHTTPCause
invalid_grant400Code expired, already used, or verifier mismatch.
invalid_client401Unknown client_id or disabled RP.
access_denied403User declined consent at /authorize.

Errors

Two error shapes appear in the identity flow:

  • OIDC / token endpoint errors (RFC 6749) — error + error_description as listed above. These come from the /token and /authorize endpoints at sso.credicorp.co.uk.
  • Hub API errors — the standard hub error envelope used by every /partner/v1/ and /public/v1/ endpoint. Branch on error.code; quote error.correlation_id to support.
json
{
  "error": {
    "code": "unauthenticated",
    "message": "A bearer access token is required.",
    "correlation_id": "cor_01J2K3M4N5P6Q7R8S9T0A1V2W3",
    "retryable": false
  }
}
codeHTTPWhen
unauthenticated401Missing or invalid access token on a hub endpoint.
token_expired401Access token has passed its expiry — refresh it.
sso_ticket_expired401SSO session ticket has passed its 120 s window.
insufficient_scope403Token not granted the scope required by the target hub endpoint.
rate_limited429Request rate over the quota; honour retry_after_ms and Retry-After. See Rate limits.
internal_error500Unexpected fault on our side. Safe to retry idempotent calls with back-off; quote correlation_id to support.
service_unavailable503Temporary maintenance or overload. Retry with back-off; check status.

The full hub error code list and envelope fields are on the Errors page.


Related: OAuth 2.0 for the underlying grant model, Accounts roadmap for what an authorised user can read, and Errors for the hub error envelope.