API Reference

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

https://identity.dxa.io.vn

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

GET /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'
const res = await fetch('https://identity.dxa.io.vn/api/session', {
  credentials: 'include', // gửi cookie xv_session
});
const session = await res.json();
if (session.authenticated && session.aal === 'AAL2') {
  console.log(session.user.email, session.memberships);
}

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

401Not signed in / session expired → `{ "authenticated": false }`
GET /step-up

Step up assurance to AAL2/AAL3 then return to the app

Auth: Cookie `xv_session` (optional)

Parameters

NameTypeDescription
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)
POST /api/auth/login

Sign in with email + password (form)

Auth: None (public)

Body parameters

FieldTypeDescription
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=1Wrong credentials (redirect with error)
POST /api/auth/2fa

Verify TOTP / recovery code (login 2FA step)

Auth: Cookie `xv_mfa` (from login step)

Body parameters

FieldTypeDescription
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.
POST /api/auth/register

Trial sign-up — creates a tenant + admin user (realm `dxa`)

Auth: None (public)

Body parameters

FieldTypeDescription
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|existsMissing field / email already exists
POST /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

GET /api/org/resolve

Resolve an organization publicly (DID + KYC verification status)

Auth: None (public, CORS *)

Parameters

NameTypeDescription
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)

POST /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

FieldTypeDescription
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
}
POST /api/did/offer

Create an OpenID4VCI Credential Offer (pre-authorized code, optional PIN)

Auth: Cookie `xv_session`

Body parameters

FieldTypeDescription
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
}
POST /api/did/verify

Verify an SD-JWT VC signature (with/without Key Binding)

Auth: None (public, CORS *)

Body parameters

FieldTypeDescription
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

400Missing credential to verify
POST /api/did/revoke

Revoke a previously issued credential

Auth: Cookie `xv_session` (credential owner)

Body parameters

FieldTypeDescription
id* string Credential ID (`vc_…`)

Example response

{ "ok": true }
GET /vc/{type}

VC type metadata (for wallet display)

Auth: None (public, CORS *)

Parameters

NameTypeDescription
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)

POST /api/oid4vci/token

Exchange a pre-authorized code for an access token + c_nonce

Auth: None (pre-authorized code flow)

Body parameters

FieldTypeDescription
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
}
POST /api/oid4vci/credential

Obtain a VC with an access token + proof-of-possession (key binding)

Auth: Bearer token (from the token endpoint)

Body parameters

FieldTypeDescription
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)

POST 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