OIDC Manual Configuration
Configure the required credentials and server values before integrating the OIDC Onboarding or Authentication flows. All values are available from your Incode dashboard.
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 secureNever expose
CLIENT_SECRET,AUTH_CLIENT_SECRET,ADMIN_EMAIL,ADMIN_PASSWORD, orAPI_KEYin 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.
Full endpoint referenceFor the complete request schema, authentication options, and error responses, see the official Admin Login API reference.
Server-side onlyThis request must be made from your server. Never expose
ADMIN_EMAIL,ADMIN_PASSWORD, orAPI_KEYin client-side code.
Request
POST /executive/log-in
Content-Type: application/json
api-version: 1.0
x-api-key: YOUR_API_KEY
{
"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
{
"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 -------------------------|
PrerequisitesBefore starting, make sure you have all required values from the Prerequisites page, including your
CLIENT_IDandCLIENT_SECRET.
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
{
"access_token": "<JWT>",
"id_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600
}
Validate the ID tokenBefore trusting any claims in the ID token, validate it using the steps in the ID Token Validation guide. Use
CLIENT_IDas the audience.
Codes are single-useAuthorization codes expire quickly (typically 60 seconds) and can only be exchanged once. If the token exchange fails, the user will need to restart the onboarding session.
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)
{
"interview_id": "667ce6cd1f9dce127eabe35e",
"email": "[email protected]"
}| Field | Description |
|---|---|
interview_id | The Incode session identifier — store this for Steps 3–5 |
email | The authenticated user's email address |
Store theinterview_idThe
interview_idis required to retrieve the verification score and OCR data. Store it securely on your server before proceeding.
Step 3: Create an Admin Token
Follow the Create Admin Token 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
Full endpoint referenceFor the complete request schema, response fields, and status definitions, see the official Get Scores API reference.
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
| Query Parameter | Required | Description |
|---|---|---|
id | No | The interview_id from Step 2. If omitted, extracted from the authentication 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 |
idValidation | Document authenticity and quality 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 |
Error Responses
| Status Code | Description |
|---|---|
400 | Bad request — check that your interview_id, api-version, and auth headers are correct |
Step 5: Retrieve OCR Data
Endpoint: GET {SERVER_URL}/omni/get/ocr-data
Full endpoint referenceFor the complete response schema and field definitions, see the official Get OCR Data API reference.
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
| Query Parameter | Required | Description |
|---|---|---|
id | No | The interview_id from Step 2. If omitted, extracted from the authentication 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();Response
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.
For the full field definitions and response schema, refer to the official Get OCR Data API reference.
Error Responses
| Status Code | Description |
|---|---|
400 | Bad request — check that your interview_id, api-version, and auth headers are correct |
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 ------------------------------|
New user?If the user has not yet been onboarded, they must complete the Onboarding flow first before they can authenticate.
PrerequisitesBefore starting, make sure you have all required values from the Prerequisites page, including your
AUTH_CLIENT_IDandAUTH_CLIENT_SECRET.
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
{
"access_token": "<JWT>",
"id_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 3600
}
Validate the ID tokenBefore trusting any claims in the ID token, validate it using the steps in the ID Token Validation guide. Use
AUTH_CLIENT_IDas the audience.
Codes are single-useAuthorization codes expire quickly (typically 60 seconds) and can only be exchanged once. If the token exchange fails, the user will need to restart the authentication session.
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)
{
"interview_id": "667ce6cd1f9dce127eabe35e",
"email": "[email protected]"
}| Field | Description |
|---|---|
interview_id | The Incode session identifier — store this for Steps 3 and 4 |
email | The authenticated user's email address |
Store theinterview_idThe
interview_idis required to retrieve the verification score. Store it securely on your server before proceeding.
Step 3: Create an Admin Token
Follow the Create Admin Token guide to obtain the admin token required for Step 4.
Step 4: Retrieve the Verification Score
Endpoint: GET {SERVER_URL}/omni/get/score
Full endpoint referenceFor the complete request schema, response fields, and status definitions, see the official Get Scores API reference.
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
| Query Parameter | Required | Description |
|---|---|---|
id | No | The interview_id from Step 2. If omitted, extracted from the authentication 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 | 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 |
Error Responses
| Status Code | Description |
|---|---|
400 | Bad request — check that your interview_id, api-version, and auth headers are correct |
Updated about 3 hours ago
