Overview

Every Aarokya endpoint is authenticated with a JSON Web Token passed as Authorization: Bearer <jwt>. Tokens come from one of two issuers:

App-user token

Issued by POST /auth/token. A partner platform’s backend exchanges a worker’s phone number and id-proof for a short-lived app JWT. This is the token mobile apps use.

OIDC token

Minted by Keycloak. Platform and benefit-provider service accounts (via client_credentials), and admin / dashboard users (via login) authenticate this way.
Once obtained, every request carries the token the same way:

Issuing an App-User Token

A partner backend authenticates as its platform service account and calls POST /auth/token. Aarokya validates the platform, find-or-creates the user by phone number, and returns an app JWT. See the Auth module for the full flow and the Platform module for provisioning the service-account credential.
1

Authenticate as the platform service account

The partner exchanges its platform credential basic_token with Keycloak (client_credentials grant) for a service-account JWT. The handler gates on actor.require_platform_service().
2

Exchange a phone number for an app token

Response 200
3

Hand the app token to the client

The mobile app receives the access_token from its own backend (not from Aarokya directly) and uses it as a Bearer token. The path user_id on user-scoped routes must match the token’s user.
id_proof.proof_type accepts AADHAAR, PAN, PASSPORT, DRIVING_LICENSE, or VOTER_ID. id_proof is consumed only when the user is first created; on repeat calls it is ignored.

App Token Reference

App JWT

Signature: RS256, verifiable with Aarokya’s public key.Claims: actor_type: "app", a user_info block (user_id, phone_number, phone_country_code, names), status, platform_id, plus iss / aud / iat / exp.Expiry: configurable (auth.app.expiry_hours).Usage: Authorization: Bearer <token> on every user-scoped request.

Token renewal

App tokens are short-lived and stateless. When one expires, the client requests a fresh one from its own backend, which re-calls POST /auth/token.
The status claim (ONBOARDING, ACTIVE, or DEACTIVATED) drives the client’s onboarding UI. A freshly created user is ONBOARDING until POST /users/{user_id}/complete_onboarding succeeds.

Renewal

Because tokens are minted server-side by the partner backend, renewal is a backend concern, not a device concern: Implement proactive renewal: when the app token is close to its exp, request a new one from your backend before the next API call rather than waiting for a 401.

Token Storage — Client

Store the app token in platform-secure storage and keep it off disk in plaintext. The token is a bearer credential: anyone holding it can act as the user until it expires.

iOS

Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly. In-memory is fine for the lifetime of the session.

Android

EncryptedSharedPreferences (API 23+), which is backed by the Android Keystore.

React Native

react-native-keychain with ACCESSIBLE.WHEN_UNLOCKED_THIS_DEVICE_ONLY — Keychain on iOS, Keystore-backed storage on Android.

Web / PWA

Keep the token in memory (JS variable / app state). Never use localStorage or sessionStorage — both are exposed to XSS.

Error Responses

Authorization failures on a specific resource (wrong scope, not the owner, admin-only) surface as that domain’s own error code — see Errors.

Security Checklist for Client Developers

Token storage

  • iOS: Keychain with kSecAttrAccessibleWhenUnlockedThisDeviceOnly
  • Android: EncryptedSharedPreferences (API 23+)
  • Web: in memory only — never localStorage / sessionStorage

Token transmission

  • Always use HTTPS in production
  • Never log tokens
  • Never put tokens in URLs or query parameters

Renewal

  • Fetch a fresh token from your backend before exp
  • Do not embed long-lived platform service-account credentials in the client

Scope

  • Use the user_id from the token for user-scoped paths
  • Clear the stored token on logout and on app reinstall