Rotate the refresh token
Operation
refreshToken- 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
| Name | In | Type | Required | Meaning | Example |
|---|---|---|---|---|---|
X-App-Version | header | string | Yes | App version `major.minor.patch+build`. Too old -> 426 `VERSION_TOO_OLD`. · pattern ^\d+\.\d+\.\d+(\+\d+)?$ | 2.0.0+200 |
X-Device-Id | header | string (uuid) | Yes | App-scoped device UUID (not ANDROID_ID). | 6b1f2c3d-0000-4000-8000-00000000d001 |
X-Request-Id | header | string (uuid) | No | Client-generated request id for tracing; echoed in responses and problems. | 0e0c5a1b-0000-4000-8000-0000000000a1 |
Accept-Language | header | string | No | Language for messages and labels. · one of en, te, ta; default "en" | te |
X-Tenant | header | string | No | Tenant code; must match the token. Urvi: `ap.gov`. · one of ap.gov | ap.gov |
Idempotency-Key | header | string (uuid) | Yes | UUID 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.
{
"refreshToken": "rt_EXAMPLE_0000000000000000000000",
"deviceId": "6b1f2c3d-0000-4000-8000-000000053249"
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
refreshToken | string | Yes | min length 20 | |
deviceId | string (uuid) | Yes |
Responses
200 New tokens.
Schema TokenResponse.
{
"accessToken": "eyJhbGciOiJSUzI1NiJ9.EXAMPLE.SIGNATURE",
"tokenType": "Bearer",
"expiresIn": 900,
"refreshToken": "rt_EXAMPLE_0000000000000000000000",
"refreshExpiresIn": 2592000,
"userId": 9001,
"tenant": "ap.gov"
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
accessToken | string | Yes | JWT, ~15 minutes. Claims: user, tenant, roles, device. | |
tokenType | string | Yes | ||
expiresIn | integer | Yes | ≥ 1 | Seconds until the access token expires. |
refreshToken | string | Yes | Rotating, device-bound, ~30 days. Store in Keystore-backed storage. | |
refreshExpiresIn | integer | Yes | ≥ 1 | |
userId | integer (int64) | No | Server id (assigned by the App Service). | |
tenant | string | No |
400 Malformed request or schema violation.
Schema Problem.
{
"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.
{
"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.
{
"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.
{
"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.
{
"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.
{
"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"
}