Overview
KRID is Katsina State's digital identity backbone. Rather than every ministry, agency, and partner building its own login and identity checks, they integrate once with KRID. The platform exposes three building blocks:
Sign in with KRID
OAuth 2.0 + OpenID Connect. Let residents log in to your app with their KRID and receive verified identity claims.
Verification API
Server-to-server checks: confirm a KRID number, cross-check NIN/BVN/DOB, or match a live face. Authenticated with an API key.
Resident API
Enrolment and profile management for citizen-facing apps, authenticated with a resident bearer token.
Who Uses KRID
Government Sectoral Solutions
Every Katsina State MDA solution (health insurance, scholarships, revenue and tax, land and housing, social welfare) uses KRID as its single source of resident identity and sign-in. One resident, one identity, across all services.
Typically integrates Sign in with KRID + the Verification API.
Approved External Partners
Banks, fintechs, telcos, NGOs, and other vetted organisations can verify Katsina residents for onboarding, KYC, eligibility, and benefits, without handling sensitive identity documents themselves.
Typically integrates the Verification API; may also offer Sign in with KRID.
Authentication
The platform uses three authentication methods, each for a different integration type:
OAuth 2.0 / OIDC
For apps that sign residents in. Redirect-based Authorization Code flow with PKCE.
Authorization: Bearer eyJhbG...API Key
For server-to-server verification by partners (e.g. KASEDA, SUBEB, a bank).
X-API-Key: ik_live_your_key_hereResident JWT
For citizen-facing calls after a resident logs in. Issued by KSAuth / login.
Authorization: Bearer eyJhbG...Getting Credentials
- Request access from the iKatsina Digital Public Infrastructure office
- State your organisation, intended use case, and estimated request volume
- Sign the Data Usage Agreement (DUA)
- Receive an OAuth client (client ID + secret, registered redirect URIs) and/or a Verification API key, each in test and production
Base URL
https://api.ikatsina.ngThere is a single base URL. Your API key prefix selects the environment: a ik_test_ key returns fixed sandbox test data and never touches the live registry, while a ik_live_ key runs against real resident records. Swap the key, not the URL, to move from testing to production.
All endpoints are prefixed with /api. The OpenID Connect discovery document is published at /api/ksauth/.well-known/openid-configuration.
Code Samples
Try the KRID Verification API right here. Pick a language and environment, paste your X-API-Key, edit the body, then press Send to run a live request — or copy the generated snippet. This example verifies a KRID number against the registry.
Language
Environment
https://api.ikatsina.ng/api/verify/krid
Same base URL for both. Your key prefix decides: ik_test_ runs against sandbox test data, ik_live_ against the live registry.
Credentials — X-API-Key
Body
curl --request POST \
--url https://api.ikatsina.ng/api/verify/krid \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header 'X-API-Key: YOUR_X_API_KEY' \
--data '{"kridNumber":"4030000000"}'Rate Limits
| Scope | Limit | Window |
|---|---|---|
| General requests | 100 / IP | per minute |
| Sensitive auth endpoints | 10 / IP | per minute |
Standard RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset headers are returned on every response. Exceeding a limit returns 429 Too Many Requests. Higher limits for production partners are arranged during onboarding.
Sign in with KRID
KSAuth is an OAuth 2.0 + OpenID Connect provider. It lets residents log in to your application with their KRID and returns verified identity claims, with no passwords for you to store. This is the primary way Katsina sectoral solutions onboard residents.
Authorization Code flow (with PKCE)
- Redirect the resident to the authorization endpoint with your client ID, redirect URI, scopes, and a PKCE challenge.
- The resident authenticates with KRID and approves the requested scopes.
- KSAuth redirects back to your registered URI with an authorization
code. - Exchange the code at the token endpoint for an ID token + access token.
- Call the userinfo endpoint with the access token to read the resident's claims.
Supported Scopes
Grant types: authorization_code, refresh_token. Response type: code. PKCE method: S256.
Discovery
Point any standard OIDC client library at the discovery URL to auto-configure endpoints, scopes, and keys:
GET https://api.ikatsina.ng/api/ksauth/\
.well-known/openid-configurationDrop-in template
Copy one of these into your app and change three values: your client ID, your client secret, and your redirect URI (it must exactly match one you registered). The Node / Express version is a complete, framework-free reference; NextAuth covers Next.js apps in a single provider block.
// server.js — "Sign in with KRID" in ~45 lines (OAuth 2.0 + PKCE).
// Change the three values marked TODO. Node 18+ (built-in fetch).
import express from 'express';
import crypto from 'crypto';
const app = express();
const KSAUTH = 'https://api.ikatsina.ng/api/ksauth';
const CLIENT_ID = process.env.KRID_CLIENT_ID; // TODO ksauth_...
const CLIENT_SECRET = process.env.KRID_CLIENT_SECRET; // TODO
const REDIRECT_URI = 'https://your-app.gov.ng/auth/krid/callback'; // TODO (must be registered)
const b64url = (buf) => buf.toString('base64url');
const pending = new Map(); // state -> code_verifier (use a session/cookie in prod)
// 1) Start login: build PKCE, then bounce the resident to KRID.
app.get('/auth/krid/login', (req, res) => {
const state = b64url(crypto.randomBytes(16));
const verifier = b64url(crypto.randomBytes(32));
const challenge = b64url(crypto.createHash('sha256').update(verifier).digest());
pending.set(state, verifier);
const url = new URL(`${KSAUTH}/oauth/authorize`);
url.search = new URLSearchParams({
response_type: 'code',
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
scope: 'openid profile email phone',
state,
code_challenge: challenge,
code_challenge_method: 'S256',
}).toString();
res.redirect(url.toString());
});
// 2) Callback: verify state, swap the code for tokens, read the claims.
app.get('/auth/krid/callback', async (req, res) => {
const { code, state } = req.query;
const verifier = pending.get(state);
if (!verifier) return res.status(400).send('Invalid state');
pending.delete(state);
const tokenRes = await fetch(`${KSAUTH}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code, redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID, client_secret: CLIENT_SECRET,
code_verifier: verifier,
}),
});
const tokens = await tokenRes.json(); // { access_token, id_token, refresh_token, ... }
const infoRes = await fetch(`${KSAUTH}/oauth/userinfo`, {
headers: { Authorization: `Bearer ${tokens.access_token}` },
});
const resident = await infoRes.json();
// { sub, resident_id, krid_number, full_name, email, phone, lga, ward, roles }
// TODO: start your own session for the resident, then redirect into your app.
res.json(resident);
});
app.listen(3000, () => console.log('http://localhost:3000/auth/krid/login'));Keep this server-side. The code-for-token exchange and ID-token check run on your server, where the client secret stays private. KSAuth signs ID tokens with HS256 (a shared secret), so a browser-only or mobile-only app cannot verify them safely — run the exchange from a backend you control.
Raw HTTP — 1. Redirect to authorize
https://api.ikatsina.ng/api/ksauth/oauth/authorize
?response_type=code
&client_id=ksauth_your_client_id
&redirect_uri=https://your-app.gov.ng/callback
&scope=openid%20profile%20email%20phone
&state=RANDOM_STATE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S2562. Exchange the code for tokens
curl -X POST https://api.ikatsina.ng/api/ksauth/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "AUTH_CODE_FROM_REDIRECT",
"redirect_uri": "https://your-app.gov.ng/callback",
"client_id": "ksauth_your_client_id",
"client_secret": "your_client_secret",
"code_verifier": "ORIGINAL_PKCE_VERIFIER"
}'Use a standard OIDC library
KSAuth is spec-compliant, so you do not need a custom SDK. Point your framework's OpenID Connect client (NextAuth, openid-client, Passport, Spring Security, ASP.NET OIDC, etc.) at the discovery URL and configure your client ID, secret, and redirect URI.
Verification API
Server-to-server endpoints for partners to verify Katsina residents. Authenticated via the X-API-Key header. Responses return only minimal, non-sensitive data.
Resident API
Endpoints that power citizen-facing apps (the KRID portal, mobile app). Enrolment is a three-step flow: verify identity, then submit the registration with the returned token. Profile reads require a resident bearer token obtained via Sign in with KRID.
Response Format
Platform endpoints return a consistent envelope. OAuth 2.0 endpoints follow the standard token/error format from the OAuth and OIDC specs.
{
"success": true,
"data": {
// Response payload
}
}{
"statusCode": 401,
"message": "Invalid API key",
"error": "Unauthorized"
}HTTP Status Codes
| Code | Meaning |
|---|---|
| 200 | Success. Request processed. |
| 201 | Created. Resident registered successfully. |
| 400 | Bad Request. Invalid input or validation error. |
| 401 | Unauthorized. Missing or invalid API key / token. |
| 403 | Forbidden. Insufficient permissions or scope. |
| 404 | Not Found. Resident or resource does not exist. |
| 409 | Conflict. Duplicate NIN, BVN, phone, or face. |
| 429 | Too Many Requests. Rate limit exceeded. |
| 502 | Bad Gateway. Upstream service temporarily unavailable. |
KRID Status Values
Every resident has a status that determines what actions they can perform:
Active, verified resident. Eligible for all services.
Registration under review. Not yet eligible.
Account temporarily suspended by admin.
Registration was rejected. Must re-apply.
Quick Start
Verify a KRID number in under 30 seconds with the Verification API. Pick your language:
curl -X POST https://api.ikatsina.ng/api/verify/krid \
-H "Content-Type: application/json" \
-H "X-API-Key: ik_live_your_api_key_here" \
-d '{"kridNumber": "8392740001"}'To add Sign in with KRID instead, point your OIDC client at the discovery URL above. See the Sign in with KRID section.
Sandbox & Testing
Build and test with a sandbox (ik_test_) key before you go live. Sandbox requests use the same base URL and endpoints as production but are answered from a fixed set of test records — they never read the live registry, so no real resident is ever affected.
Point your integration at https://api.ikatsina.ng and send your ik_test_ key in the X-API-Key header. Use the test KRID numbers below to exercise the verified, mismatch, and not-found paths. Every sandbox response includes "sandbox": true.
Test Credentials
https://api.ikatsina.ngyour ik_test_… keyTest KRID Numbers
| KRID | Behaviour |
|---|---|
| 4030000000 | VERIFIEDIdentity + face MATCH |
| 4030000001 | MISMATCHIdentity + face DO NOT match |
| 0000000000 | NOT FOUNDKRID not in registry |
For 4030000000, pass nin/bvn 12345678901 and dateOfBirth 1990-01-01 to get a full match; send any other value on those fields to see the mismatch response.
Important
Sandbox keys only ever see the fixed test records above — they cannot reach live resident data. When you are ready for production, swap in your ik_live_ key on the same base URL. Test keys begin with ik_test_, production keys with ik_live_.
Support
Integration Support
For help with API integration, OAuth onboarding, and technical issues.
api-support@ikatsina.ngPartner Onboarding
Request API keys, register an OAuth client, or sign the Data Usage Agreement.
developers@ikatsina.ngData Privacy
The Verification API returns only minimal, non-sensitive data (first name, last name, LGA, state). Sensitive fields like NIN, BVN, phone, email, and face images are never returned. Sign-in claims are limited to the scopes the resident consents to. All verification and authentication requests are logged with the partner/client ID for audit compliance.