OIDC Manual Configuration
Prerequisites
The following values are required for both the Onboarding and Authentication flows. You will need them from your Incode dashboard and OIDC configuration.
Shared Values
| Value | Description |
|---|---|
AUTH_SERVER_URL |
Base URL of the OIDC authorization server (https://auth.demo.incode.com). Also used as the issuer value for ID token validation. |
SERVER_URL |
Base URL of the Incode API server |
REDIRECT_URI |
The redirect URI registered with your OIDC client |
API_KEY |
Your Incode API key |
ADMIN_EMAIL |
Admin account email for the Incode Admin API |
ADMIN_PASSWORD |
Admin account password for the Incode Admin API |
Onboarding Client Credentials
| Value | Description |
|---|---|
CLIENT_ID |
Your registered OIDC onboarding client ID |
CLIENT_SECRET |
Your registered OIDC onboarding client secret |
Authentication Client Credentials
| Value | Description |
|---|---|
AUTH_CLIENT_ID |
Your registered OIDC authentication client ID |
AUTH_CLIENT_SECRET |
Your registered OIDC authentication client secret |
Keep credentials secure
Never expose CLIENT_SECRET, AUTH_CLIENT_SECRET, ADMIN_EMAIL, ADMIN_PASSWORD, or API_KEY in client-side code. All requests using these values must be made from your server.
ID Token Validation
After receiving an ID token from the /oauth2/token endpoint, your application is responsible for validating it before trusting any of its claims. Use a well-maintained JWT library rather than implementing validation manually.
Recommended Libraries
| Language | Library |
|---|---|
| JavaScript / Node.js | jose, jsonwebtoken |
| Python | python-jose, authlib |
| Java | nimbus-jose-jwt |
| Go | golang-jwt/jwt |
| Ruby | jwt |
Claims to Validate
| Claim | Expected Value | Why |
|---|---|---|
iss |
Must exactly match https://auth.demo.incode.com |
Confirms the token was issued by the authorization server you trust |
exp |
Must be in the future (compare against server time) | Rejects expired tokens |
nonce |
Must match the nonce sent during the session |
Confirms the token was issued in response to your specific request — protects against replay attacks |
azp |
Must equal your CLIENT_ID when multiple audiences are present |
Confirms your app is the intended recipient of the token |
kid |
Must be present in the JWKS at https://auth.demo.incode.com/oauth2/jwks |
Used to verify the token's cryptographic signature |
Verifying the Token Signature (JWKS)
The kid value in the token header identifies which public key to use for signature verification. Fetch Incode's public keys and find the matching key:
GET https://auth.demo.incode.com/oauth2/jwks
Example (JavaScript using jose)
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(
new URL('https://auth.demo.incode.com/oauth2/jwks')
);
const { payload } = await jwtVerify(idToken, JWKS, {
issuer: 'https://auth.demo.incode.com',
audience: CLIENT_ID, // Use AUTH_CLIENT_ID for the Authentication flow
});
// Validate nonce manually
if (payload.nonce !== storedNonce) {
throw new Error('Nonce mismatch — possible replay attack');
}
Create Admin Token
Endpoint:POST {SERVER_URL}/executive/log-in
Before retrieving verification results, your server must authenticate with the Incode Admin API to obtain a short-lived, high-privilege admin token.
Request
POST /executive/log-in
Content-Type: application/json
api-version: 1.0
x-api-key: YOUR_API_KEY
JSON
{
"email": "YOUR_ADMIN_EMAIL",
"password": "YOUR_ADMIN_PASSWORD"
}
Example (JavaScript)
const response = await fetch(`${SERVER_URL}/executive/log-in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'api-version': '1.0',
'x-api-key': API_KEY,
},
body: JSON.stringify({
email: ADMIN_EMAIL,
password: ADMIN_PASSWORD,
}),
});
const { token: adminToken } = await response.json();
Response
JSON
{
"token": "<admin-token>"
}
| Field | Description |
|---|---|
token |
Short-lived admin token required for score and OCR data retrieval |
OIDC Onboarding Demo
Overview
The OIDC Onboarding flow verifies a new user's identity by combining OpenID Connect (OIDC) with Incode's biometric verification pipeline. Once the user completes the onboarding session on the frontend, your server exchanges the resulting authorization code for tokens and retrieves the full verification and document data.
High-level flow:
Your Server Auth Server (OIDC) Incode API
| | |
|-- 1. POST /token ------>| |
|<-- access + id token ---| |
|-- 2. GET /userinfo ---->| |
|<-- interview_id --------| |
|-- 3. POST /executive/log-in ----------------------->|
|<-- adminToken ----------------------------------------|
|-- 4. GET /omni/get/score -------------------------->|
|<-- verification score ------------------------------|
|-- 5. GET /omni/get/ocr-data ----------------------->|
|<-- extracted document data -------------------------|
Step 1: Exchange the Authorization Code for Tokens
Endpoint:POST {AUTH_SERVER_URL}/oauth2/token
Once the user has completed the onboarding session on the frontend, your server receives an authorization code. Exchange it for an access token and ID token using your CLIENT_SECRET.
Request
POST /oauth2/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
| Parameter | Value |
|---|---|
grant_type |
authorization_code |
client_id |
YOUR_CLIENT_ID |
client_secret |
YOUR_CLIENT_SECRET |
redirect_uri |
YOUR_REDIRECT_URI |
code |
The authorization code received from the onboarding session |
Example (JavaScript)
const response = await fetch(`${AUTH_SERVER_URL}/oauth2/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code: authorizationCode,
}),
});
const tokens = await response.json();
Response
JSON
{
"access_token": "<JWT>",
"id_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600
}
Step 2: Retrieve the Interview ID
Endpoint:GET {AUTH_SERVER_URL}/userinfo
Once your application has a valid access token, call the OIDC UserInfo endpoint to retrieve the interview_id for the onboarding session.
Request
GET /userinfo
Authorization: Bearer YOUR_ACCESS_TOKEN
Example (JavaScript)
const response = await fetch(`${AUTH_SERVER_URL}/userinfo`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
},
});
const userInfo = await response.json();
const interviewId = userInfo.interview_id;
Response (example)
JSON
{
"interview_id": "667ce6cd1f9dce127eabe35e",
"email": "user@example.com"
}
Step 3: Create an Admin Token
Follow the guide to obtain the admin token required for Steps 4 and 5.
Step 4: Retrieve the Verification Score
Endpoint:GET {SERVER_URL}/omni/get/score
Request
GET /omni/get/score?id=YOUR_INTERVIEW_ID
Content-Type: application/json
api-version: 1.0
x-api-key: YOUR_API_KEY
X-Incode-Hardware-Id: YOUR_ADMIN_TOKEN
Example (JavaScript)
const response = await fetch(
`${SERVER_URL}/omni/get/score?id=${interviewId}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'api-version': '1.0',
'x-api-key': API_KEY,
'X-Incode-Hardware-Id': adminToken,
},
}
);
const score = await response.json();
Response
| Section | Description |
|---|---|
overall |
Composite score and pass/fail status across all checks |
liveness |
Liveness detection results |
faceRecognition |
Selfie-to-ID face match results |
deepsight |
Multimodal fraud intelligence signals |
idOcrConfidence |
Confidence scores for extracted text fields |
governmentValidation |
Government database cross-check results |
watchlistScore |
Watchlist screening results |
antifraud |
Aggregate fraud risk assessment |
deviceRisk |
Device trust signals |
behavioralRisk |
Behavioral trust signals |
reasonMsg |
Human-readable explanation of the overall outcome |
Step 5: Retrieve OCR Data
Endpoint:GET {SERVER_URL}/omni/get/ocr-data
Request
GET /omni/get/ocr-data?id=YOUR_INTERVIEW_ID
Content-Type: application/json
api-version: 1.0
x-api-key: YOUR_API_KEY
X-Incode-Hardware-Id: YOUR_ADMIN_TOKEN
Example (JavaScript)
const response = await fetch(
`${SERVER_URL}/omni/get/ocr-data?id=${interviewId}`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
'api-version': '1.0',
'x-api-key': API_KEY,
'X-Incode-Hardware-Id': adminToken,
},
}
);
const ocrData = await response.json();
A successful response returns a 200 OK containing data extracted from the user's identity document and address statement, including fields such as name, date of birth, address, document number, and expiration date.
Authentication
Overview
The OIDC Authentication flow allows a previously onboarded user to authenticate using face recognition. This is a 1:N flow — the authorization server matches the user's face against the full enrolled population without requiring a known user identifier upfront.
High-level flow:
Your Server Auth Server (OIDC) Incode API
| | |
|-- 1. POST /token ------>| |
|<-- access + id token ---| |
|-- 2. GET /userinfo ---->| |
|<-- interview_id --------| |
|-- 3. POST /executive/log-in ----------------------->|
|<-- adminToken ----------------------------------------|
|-- 4. GET /omni/get/score -------------------------->|
|<-- verification score ------------------------------|
Step 1: Exchange the Authorization Code for Tokens
Endpoint:POST {AUTH_SERVER_URL}/oauth2/token
Once the user has completed the face authentication session on the frontend, your server receives an authorization code. Exchange it for an access token and ID token using your AUTH_CLIENT_SECRET.
Request
POST /oauth2/token
Content-Type: application/x-www-form-urlencoded
Accept: application/json
| Parameter | Value |
|---|---|
grant_type |
authorization_code |
client_id |
YOUR_AUTH_CLIENT_ID |
client_secret |
YOUR_AUTH_CLIENT_SECRET |
redirect_uri |
YOUR_REDIRECT_URI |
code |
The authorization code received from the authentication session |
Example (JavaScript)
const response = await fetch(`${AUTH_SERVER_URL}/oauth2/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: AUTH_CLIENT_ID,
client_secret: AUTH_CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code: authorizationCode,
}),
});
const tokens = await response.json();
Response
JSON
{
"access_token": "<JWT>",
"id_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600
}
Step 2: Retrieve the Interview ID
Endpoint:GET {AUTH_SERVER_URL}/userinfo
Once your application has a valid access token, call the OIDC UserInfo endpoint to retrieve the interview_id for the authentication session.
Request
GET /userinfo
Authorization: Bearer YOUR_ACCESS_TOKEN
Example (JavaScript)
const response = await fetch(`${AUTH_SERVER_URL}/userinfo`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
},
});
const userInfo = await response.json();
const interviewId = userInfo.interview_id;
Response (example)
JSON
{
"interview_id": "667ce6cd1f9dce127eabe35e",
"email": "user@example.com"
}
Step 3: Create an Admin Token
Follow the guide to obtain the admin token required for Step 4.
Step 4: Retrieve the Verification Score
Endpoint:GET {SERVER_URL}/omni/get/score
Request
Example (JavaScript)
const score = await response.json();
**Response**
| Section | Description |
|----------------------|-----------------------------------------------------------|
| `overall` | Composite score and pass/fail status across all checks |
| `liveness` | Liveness detection results |
| `faceRecognition` | Face match results against the enrolled user |
| `deepsight` | Multimodal fraud intelligence signals |
| `antifraud` | Aggregate fraud risk assessment |
| `deviceRisk` | Device trust signals |
| `behavioralRisk` | Behavioral trust signals |
| `reasonMsg` | Human-readable explanation of the overall outcome |