DXA Identity API
Identity, SSO & authentication for the whole ecosystem
DXA Identity is a central multi-realm CIAM service. Every product shares one sign-in session (SSO) via the `xv_session` cookie on the `.dxa.io.vn` domain. Integrating apps authenticate users through the introspection endpoint, redirect to the central sign-in page, or step up assurance when needed. It also supports decentralized identity (DID/VC), digital wallets (OpenID4VCI), and machine-to-machine auth (service clients).
Base URL
Authentication
Lucia-style sessions: the token lives in the `xv_session` cookie (HttpOnly, Domain=.dxa.io.vn). To authenticate a user from your app, call `GET /api/session` with the cookie — the browser sends it automatically to every subdomain. The default realm is `dxa`. Sessions record the authentication methods (`amr`) and assurance level (`aal`: AAL1/AAL2/AAL3). Machine-to-machine integrations use a service-client Bearer token.
Authentication & Session
/api/session Introspect the current session — with amr/aal (CORS for *.dxa.io.vn)
Auth: Cookie `xv_session` (auto-sent)
Example request
curl 'https://identity.dxa.io.vn/api/session' \
-H 'Cookie: xv_session=<token>' \
-H 'Origin: https://your-app.dxa.io.vn' Example response
{
"authenticated": true,
"realmId": "dxa",
"user": {
"id": "usr_8f2c…",
"email": "dev@partner.vn",
"name": "Nguyễn An",
"avatar_color": "#24467e"
},
"memberships": [
{ "org_id": "org_12ab", "org_name": "Đối tác ABC", "role": "admin" }
],
"amr": ["pwd", "otp"],
"aal": "AAL2"
} Error codes
401 | Not signed in / session expired → `{ "authenticated": false }` |
/step-up Step up assurance to AAL2/AAL3 then return to the app
Auth: Cookie `xv_session` (optional)
Parameters
| Name | Type | Description |
|---|---|---|
redirect* | string | Return URL (must be *.dxa.io.vn or localhost) |
aal | 'AAL1' | 'AAL2' | 'AAL3' | Required assurance level (default AAL2) |
Example request
https://identity.dxa.io.vn/step-up
?aal=AAL2
&redirect=https://your-app.dxa.io.vn/secure-action Example response
// 302 Redirect:
// • Phiên hiện tại đã đạt mức AAL yêu cầu → quay lại <redirect>
// • Chưa đạt / chưa đăng nhập → /login?aal=AAL2&redirect=<url> (buộc xác thực lại) /api/auth/login Sign in with email + password (form)
Auth: None (public)
Body parameters
| Field | Type | Description |
|---|---|---|
email* | string | User email |
password* | string | Password |
realm | string | Realm (default `dxa`) |
Example request
curl -X POST 'https://identity.dxa.io.vn/api/auth/login' \
-H 'Origin: https://identity.dxa.io.vn' \
-F 'email=dev@partner.vn' \
-F 'password=••••••••' Example response
// 303 Redirect — đặt cookie xv_session, chuyển tới /account hoặc redirect đã validate.
// Nếu user bật 2FA → chuyển sang /login/2fa (đặt cookie xv_mfa tạm thời). Error codes
303 ?error=1 | Wrong credentials (redirect with error) |
/api/auth/2fa Verify TOTP / recovery code (login 2FA step)
Auth: Cookie `xv_mfa` (from login step)
Body parameters
| Field | Type | Description |
|---|---|---|
code* | string | 6-digit TOTP or recovery code |
Example response
// 303 Redirect — tạo phiên thật (amr: ["pwd","otp"], aal: AAL2),
// đặt cookie xv_session và xoá cookie xv_mfa. /api/auth/register Trial sign-up — creates a tenant + admin user (realm `dxa`)
Auth: None (public)
Body parameters
| Field | Type | Description |
|---|---|---|
email* | string | Admin email |
password* | string | Password (min 6 chars) |
name* | string | User name |
orgName* | string | Organization (tenant) name |
Example response
// 303 Redirect — đặt cookie xv_session, chuyển tới /account. Error codes
303 ?error=invalid|exists | Missing field / email already exists |
/api/auth/logout Sign out — invalidate session & clear cookie
Auth: Cookie `xv_session`
Example response
// 303 Redirect — xoá cookie xv_session/xv_org, chuyển về /login. Organizations
/api/org/resolve Resolve an organization publicly (DID + KYC verification status)
Auth: None (public, CORS *)
Parameters
| Name | Type | Description |
|---|---|---|
org_id | string | Organization ID (or use `slug`) |
slug | string | Organization slug (or use `org_id`) |
Example request
curl 'https://identity.dxa.io.vn/api/org/resolve?slug=doi-tac-abc' Example response
{
"org_id": "org_12ab",
"name": "Đối tác ABC",
"did": "did:web:identity.dxa.io.vn",
"org_did": "did:web:identity.dxa.io.vn:o:org_12ab",
"verified": true,
"verified_at": "2026-05-01T00:00:00Z",
"realm": "dxa"
} Decentralized Identity (DID / VC)
/api/did/issue Issue a Verifiable Credential (SD-JWT) to a user or organization
Auth: Cookie `xv_session`, or a service-client Bearer token (scope `did:issue`)
Body parameters
| Field | Type | Description |
|---|---|---|
type* | 'IdentityCredential' | 'MembershipCredential' | 'OrganizationAttestation' | Credential type |
org_id | string | Organization (required for OrganizationAttestation; optional for Membership) |
claims | object | Custom claims (OrganizationAttestation only) |
Example response
{
"id": "vc_7d21…",
"type": "IdentityCredential",
"vct": "https://identity.dxa.io.vn/vc/IdentityCredential",
"issuer": "did:web:identity.dxa.io.vn",
"subject": "did:web:identity.dxa.io.vn:u:usr_8f2c",
"claims": { "email": "dev@partner.vn", "name": "Nguyễn An" },
"sdjwt": "eyJhbGciOiJFUzI1Ni…~WyJ…",
"issuedAt": "2026-06-01T00:00:00Z",
"expiresAt": 1798675200
} /api/did/offer Create an OpenID4VCI Credential Offer (pre-authorized code, optional PIN)
Auth: Cookie `xv_session`
Body parameters
| Field | Type | Description |
|---|---|---|
type | string | Credential type (or `types` array) |
org_id | string | Organization (for MembershipCredential) |
pin | boolean | Enable a PIN (tx_code) to protect the offer |
Example response
{
"offer": {
"credential_issuer": "https://identity.dxa.io.vn",
"credential_configuration_ids": ["IdentityCredential"],
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "…",
"tx_code": { "length": 4, "input_mode": "numeric" }
}
}
},
"offerUri": "openid-credential-offer://?credential_offer=…",
"txCode": "1234",
"expiresAt": 1798675200
} /api/did/verify Verify an SD-JWT VC signature (with/without Key Binding)
Auth: None (public, CORS *)
Body parameters
| Field | Type | Description |
|---|---|---|
token* | string | The SD-JWT string to verify (also accepts `sdjwt`/`credential`) |
nonce | string | Nonce for Key Binding validation |
Example request
curl -X POST 'https://identity.dxa.io.vn/api/did/verify' \
-H 'Content-Type: application/json' \
-d '{ "token": "eyJhbGciOiJF…" }' Example response
{
"valid": true,
"iss": "did:web:identity.dxa.io.vn",
"sub": "did:web:identity.dxa.io.vn:u:usr_8f2c",
"vct": "https://identity.dxa.io.vn/vc/IdentityCredential",
"payload": { "email": "dev@partner.vn", "name": "Nguyễn An" },
"exp": 1798675200,
"iat": 1767139200
} Error codes
400 | Missing credential to verify |
/api/did/revoke Revoke a previously issued credential
Auth: Cookie `xv_session` (credential owner)
Body parameters
| Field | Type | Description |
|---|---|---|
id* | string | Credential ID (`vc_…`) |
Example response
{ "ok": true } /vc/{type} VC type metadata (for wallet display)
Auth: None (public, CORS *)
Parameters
| Name | Type | Description |
|---|---|---|
type* | 'IdentityCredential' | 'MembershipCredential' | 'OrganizationAttestation' | VC type in the path |
Example response
{
"vct": "https://identity.dxa.io.vn/vc/IdentityCredential",
"name": "DXA Identity",
"description": "…",
"claims": {
"email": { "name": "Email", "required": true },
"name": { "name": "Họ tên" }
}
} Digital wallet (OpenID4VCI)
/api/oid4vci/token Exchange a pre-authorized code for an access token + c_nonce
Auth: None (pre-authorized code flow)
Body parameters
| Field | Type | Description |
|---|---|---|
grant_type* | string | `urn:ietf:params:oauth:grant-type:pre-authorized_code` |
pre-authorized_code* | string | Code from the Credential Offer |
tx_code | string | PIN (if the offer is PIN-protected) |
Example response
{
"access_token": "…",
"token_type": "bearer",
"expires_in": 600,
"c_nonce": "…",
"c_nonce_expires_in": 600
} /api/oid4vci/credential Obtain a VC with an access token + proof-of-possession (key binding)
Auth: Bearer token (from the token endpoint)
Body parameters
| Field | Type | Description |
|---|---|---|
credential_configuration_id* | string | Credential type, e.g. `IdentityCredential` |
proof* | object | A JWT proof (`proof_type: "jwt"`) carrying the wallet public key in the header |
Example response
{
"credentials": [ { "credential": "eyJhbGciOiJF…" } ],
"credential": "eyJhbGciOiJF…"
} Machine-to-machine (Service client)
Authorization: Bearer <service_token> Machine-to-machine auth for server-side operations (e.g. issuing org VCs)
Auth: Service-client Bearer token (token_hash stored in D1, scoped)
Example request
curl -X POST 'https://identity.dxa.io.vn/api/did/issue' \
-H 'Authorization: Bearer <service_token>' \
-H 'Content-Type: application/json' \
-d '{ "type": "OrganizationAttestation", "org_id": "org_12ab",
"claims": { "docType": "invoice", "docId": "INV-2026-001" } }' Example response
// Service client là tài khoản máy gắn với một realm/tổ chức và danh sách scope.
// Dùng cho luồng đầu-cuối không có người dùng — ví dụ DXA Blockchain/Trustway
// gọi /api/did/issue với scope ["did:issue"] để cấp OrganizationAttestation.
//
// Authorization: Bearer <service_token>
// • token_hash = sha256(token) lưu trong bảng service_clients
// • scopes: ["did:issue", …] • org_id: null = mọi tổ chức trong realm