API contracts / App Service v2 / Auth & session

Rotate the refresh token

OperationrefreshToken
Call
POST /gateway/urvi-app-service/api/v2/auth/refresh
Group
Auth & session
Features
Login, App startup and role detection, Pending sync
Replaces today

Use case. Called by the HTTP client's authenticator when any call returns 401 TOKEN_EXPIRED (once), and by the sync worker before a batch if the access token is near expiry. Returns a new access token and a new refresh token (rotation); the old refresh token becomes invalid. On failure the app shows "Session expired, log in" and keeps the outbox intact. Replaces the silent re-login with a stored password.

Rules.

  • Refresh tokens are bound to deviceId; a token presented from another device is revoked -> REFRESH_TOKEN_INVALID.
  • Reuse of a rotated refresh token revokes the whole token family.

Error codes. REFRESH_TOKEN_INVALID, DEVICE_BLOCKED

Parameters

NameInTypeRequiredMeaningExample
X-App-VersionheaderstringYesApp version `major.minor.patch+build`. Too old -> 426 `VERSION_TOO_OLD`. · pattern ^\d+\.\d+\.\d+(\+\d+)?$2.0.0+200
X-Device-Idheaderstring (uuid)YesApp-scoped device UUID (not ANDROID_ID).6b1f2c3d-0000-4000-8000-00000000d001
X-Request-Idheaderstring (uuid)NoClient-generated request id for tracing; echoed in responses and problems.0e0c5a1b-0000-4000-8000-0000000000a1
Accept-LanguageheaderstringNoLanguage for messages and labels. · one of en, te, ta; default "en"te
X-TenantheaderstringNoTenant code; must match the token. Urvi: `ap.gov`. · one of ap.govap.gov
Idempotency-Keyheaderstring (uuid)YesUUID per write request; retained >= 30 days. Reusing a key with a different body -> 422 `IDEMPOTENCY_KEY_REUSED`.9c8b7a6d-0000-4000-8000-0000000000b1

Request

Body schema RefreshRequest.

Example request body
{
  "refreshToken": "rt_EXAMPLE_0000000000000000000000",
  "deviceId": "6b1f2c3d-0000-4000-8000-000000053249"
}
FieldTypeRequiredRulesMeaning
refreshTokenstringYesmin length 20
deviceIdstring (uuid)Yes

Responses

200 New tokens.

Schema TokenResponse.

Example 200 body
{
  "accessToken": "eyJhbGciOiJSUzI1NiJ9.EXAMPLE.SIGNATURE",
  "tokenType": "Bearer",
  "expiresIn": 900,
  "refreshToken": "rt_EXAMPLE_0000000000000000000000",
  "refreshExpiresIn": 2592000,
  "userId": 9001,
  "tenant": "ap.gov"
}
FieldTypeRequiredRulesMeaning
accessTokenstringYesJWT, ~15 minutes. Claims: user, tenant, roles, device.
tokenTypestringYes
expiresInintegerYes≥ 1Seconds until the access token expires.
refreshTokenstringYesRotating, device-bound, ~30 days. Store in Keystore-backed storage.
refreshExpiresInintegerYes≥ 1
userIdinteger (int64)NoServer id (assigned by the App Service).
tenantstringNo

400 Malformed request or schema violation.

Schema Problem.

Example 400 body
{
  "type": "https://urvi.example.invalid/problems/validation-failed",
  "title": "Validation failed",
  "status": 400,
  "detail": "One or more fields are invalid.",
  "code": "VALIDATION_FAILED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "errors": [
    {
      "field": "/mobile",
      "code": "INVALID_MOBILE",
      "message": "Mobile must be 10 digits starting 6-9."
    }
  ]
}

401 Refresh token invalid or expired; log in again.

Schema Problem.

Example 401 body
{
  "type": "https://urvi.example.invalid/problems/refresh-token-invalid",
  "title": "Session expired",
  "status": 401,
  "detail": "Please log in again.",
  "code": "REFRESH_TOKEN_INVALID",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

403 Authenticated but not allowed (role, tenant, device binding or feature switch).

Schema Problem.

Example 403 body
{
  "type": "https://urvi.example.invalid/problems/role-not-allowed",
  "title": "Not allowed",
  "status": 403,
  "detail": "Your role cannot perform this action.",
  "code": "ROLE_NOT_ALLOWED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}

426 App version below the minimum; block the UI with an update prompt. Pending outbox ops are kept.

Schema Problem.

Example 426 body
{
  "type": "https://urvi.example.invalid/problems/version-too-old",
  "title": "Update required",
  "status": 426,
  "detail": "Please update Urvi to continue.",
  "code": "VERSION_TOO_OLD",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "minAppVersion": "2.0.0"
}

429 Rate limited per device / user. Respect `Retry-After`.

Schema Problem.

Example 429 body
{
  "type": "https://urvi.example.invalid/problems/rate-limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "Slow down and retry later.",
  "code": "RATE_LIMITED",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1",
  "retryAfterSeconds": 30
}

500 Unexpected server error; retry with backoff (writes are idempotent).

Schema Problem.

Example 500 body
{
  "type": "https://urvi.example.invalid/problems/internal-error",
  "title": "Server error",
  "status": 500,
  "detail": "Something went wrong. Please try again.",
  "code": "INTERNAL_ERROR",
  "requestId": "0e0c5a1b-0000-4000-8000-0000000000a1"
}