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": "[email protected]",
  "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.

Related: OAuth 2.0 for the underlying grant model, Accounts for what an authorised user can read, and Errors for the standard error/error_description shape returned by the token endpoint.