OIDC Integration
DecideID OIDC Integration Guide
Overview
DecideID offers a full-featured OpenID Connect (OIDC) provider that enables application developers to integrate proof-of-humanity (PoH) verification and user reputation data into any web or mobile application. Built on the Internet Computer Protocol (ICP), DecideID ensures decentralized identity management with strong privacy guarantees.
Key Features
Proof of Humanity: Confirm users are unique humans, not bots.
Reputation Levels: Access user trust levels (e.g., Silver, Gold).
Decentralized Infrastructure: Powered by the Internet Computer.
Privacy-Centric Design: User-controlled data consent and access.
OIDC Standard Compliance: Integrates with any OAuth 2.0/OIDC-compatible libraries.
Supported Scopes
poh — Returns verification status and reputation data.
Getting Started
Prerequisites
A DecideID developer account
Familiarity with OAuth 2.0 / OIDC flows
HTTPS-enabled redirect URIs for production environments
Available Environments
UI / Authorization Endpoint: Uses a user-facing canister for login flow.
API Endpoint: Uses the backend canister for token and user data access.
Developer Portal
Access the Dashboard
Sign up or log in using your email address.
Navigate to the "OIDC Clients" section.

Register a New Client
Click Register New Client
Complete the form:
Client ID: Unique identifier
App Name: Display name for user consent screens
Redirect URIs: Allowed callback URLs (must be HTTPS)
Scopes: Default scope is
poh
Click Register Client
Save your Client ID and Client Secret securely

Manage Clients
View registered clients
Edit and regenerate client credentials — coming soon

OIDC Authorization Code Flow
Authorization Request: Redirect user to authorization endpoint
User Consent: User reviews and grants permissions
Authorization Code: Returned to your app’s redirect URI
Token Exchange: Use code to retrieve access and ID tokens
User Info: Use access token to retrieve identity details
API Reference
Base URL (Production)
https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io
OpenID Configuration
GET /.well-known/openid-configuration
Returns:
{
"issuer": "https://id.decideai.xyz",
"authorization_endpoint": "https://id.decideai.xyz/#/authorize",
"token_endpoint": "https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io/token",
"userinfo_endpoint": "https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io/userinfo",
"jwks_uri": "https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io/.well-known/jwks.json",
"response_types_supported": ["code"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["ES256K"]
}
JWKS
GET /.well-known/jwks.json
Returns JSON Web Keys for validating ID tokens.
Authorization Request
GET /authorize
Required query parameters:
client_id
redirect_uri
response_type=code
scope=poh
state=random-string
Example:
https://id.decideai.xyz/#/authorize?client_id=my-app&redirect_uri=https%3A%2F%2Fmyapp.com%2Fcallback&response_type=code&scope=poh&state=xyz123
Token Exchange
POST /token
Headers:
Content-Type: application/x-www-form-urlencoded
Body:
grant_type=authorization_code&code=CODE&client_id=ID&client_secret=SECRET&redirect_uri=URI
Response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "poh",
"id_token": "..."
}
User Info Endpoint
GET /userinfo?scope=poh
Headers:
Authorization: Bearer ACCESS_TOKEN
Response (scope = poh):
Response Object
sub - A unique user id attatched the user
verified - Whether the user currently has a valid proof of humanity credential.
reputation_level - The users current reputation level
gold: The highest reputation level. Requires a reverification of the account at least once. Note, we will assign "gold" status for 2 weeks for new accounts and then they will transition to "silver" this is so that we don't penalize new accounts. In the future these rules may change.
silver: Users are automatically downgraded to silver after two weeks, requiring reverification to regain gold status.
verification_date - The date the user last perfromed a verification. Not necessarily a successful verification.
{
"sub": "unique-user-id",
"verified": true, // If they are currently verified
"reputation_level": "gold", // Either "gold" or "silver"
"verification_date": "2024-01-15T10:30:00Z" // When they were last verified
}
Token Structure Example (Decoded JWT)
ID Token
{
"iss": "https://id.decideai.xyz",
"sub": "user-unique-id",
"aud": "your-client-id",
"exp": 1712345678,
"iat": 1712341678,
"scope": "poh"
}
Access Token (Example payload)
{
"sub": "user-unique-id",
"verified": true,
"reputation_level": "Silver"
}
Sample App: Node.js + Express
const express = require('express');
const axios = require('axios');
const qs = require('querystring');
const app = express();
const CLIENT_ID = 'YOUR_CLIENT_ID';
const CLIENT_SECRET = 'YOUR_CLIENT_SECRET';
const REDIRECT_URI = 'https://yourapp.com/callback';
// STEP 1: Redirect user to the authorization screen
app.get('/login', (req, res) => {
const authUrl = `https://id.decideai.xyz/#/authorize?client_id=${CLIENT_ID}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&response_type=code&scope=poh&state=random123`;
res.redirect(authUrl);
});
// STEP 2: Handle the redirect URI callback with authorization code
app.get('/callback', async (req, res) => {
const { code } = req.query;
const tokenUrl = 'https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io/token';
try {
// STEP 3: Exchange authorization code for access + ID tokens
const tokenResponse = await axios.post(tokenUrl, qs.stringify({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
}), {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
const { access_token, id_token } = tokenResponse.data;
// STEP 4: Use the access token to fetch user's PoH verification status
const userInfoResponse = await axios.get('https://rlz47-aqaaa-aaaah-qdcra-cai.icp0.io/userinfo?scope=poh', {
headers: {
Authorization: `Bearer ${access_token}`
}
});
// STEP 5: Display user info result (or pass to your frontend/session)
res.json({
id_token,
user_info: userInfoResponse.data
});
} catch (error) {
console.error('Error during callback handling:', error.response?.data || error.message);
res.status(500).send('OIDC login failed');
}
});
app.listen(3000, () => console.log('App running on http://localhost:3000'));
Consent Screen Preview
When users are redirected to the authorization endpoint, they see a branded DecideID login and authorization interface.
Step 1: Sign In Screen
Branded with the DecideID logo and name.
Shows the requesting app (e.g., OpenChat).
Prompts users to continue with Internet Identity.
Includes an option to create a new DecideID account if the user doesn’t already have one.
Step 2: Authorization Screen
Clearly states that the application wants access to your DecideID account.
Lists the specific permissions requested (e.g., Proof of Humanity verification status).
Provides "Authorize" and "Cancel" buttons.
Displays a reminder that access can be revoked at any time via account settings.
Screenshots:


Error Handling
Format:
{
"error": "error_code",
"error_description": "Explanation"
}
Common Errors
invalid_client: Check client credentials
invalid_grant: Authorization code expired or invalid
invalid_request: Redirect URI mismatch
invalid_scope: Scope not recognized (currently only
poh
is supported)
Testing & Debugging
Use the development environment for integration testing
Walk through the full flow manually
Validate JWTs using the JWKS endpoint
Check for HTTPS and URI mismatches
Log non-sensitive API responses for diagnostics
Security Best Practices
Never expose
client_secret
in frontend codeAlways use HTTPS for redirects
Validate the
state
parameter for CSRF protectionUse secure storage for tokens
Implement token expiration handling
Support
Refer to OIDC Specs
Contact the DecideID support team for integration issues
Last updated