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

  1. Sign up or log in using your email address.

  2. Navigate to the "OIDC Clients" section.

Register a New Client

  1. Click Register New Client

  2. 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

  3. Click Register Client

  4. Save your Client ID and Client Secret securely

Manage Clients

  • View registered clients

  • Edit and regenerate client credentials — coming soon


OIDC Authorization Code Flow

  1. Authorization Request: Redirect user to authorization endpoint

  2. User Consent: User reviews and grants permissions

  3. Authorization Code: Returned to your app’s redirect URI

  4. Token Exchange: Use code to retrieve access and ID tokens

  5. 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'));

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:

Authorization request with Login
Authorization prompt with permission summary

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 code

  • Always use HTTPS for redirects

  • Validate the state parameter for CSRF protection

  • Use secure storage for tokens

  • Implement token expiration handling


Support

Last updated