Log in with login, tenant and password
login- Call
POST /gateway/urvi-app-service/api/v2/auth/login- Group
- Auth & session
- Features
- Login, App startup and role detection
- Replaces today
Use case. Called by the Login screen on first launch (online only) and after "Session expired". The app sends the trimmed, lower-cased login, the tenant and the password together with its app-scoped device id; the App Service authenticates against Bridge server-side, resolves the tenant (including the federated ap.gov host), binds the refresh token to the device and returns short-lived tokens. The app stores only the refresh token (Keystore-backed) and immediately calls GET /session/bootstrap. The password is never persisted on the phone.
Rules.
- Login shapes accepted:
email,login@@tenant, numeric IE login; a plain email gets@@tenantappended. - Unknown tenant -> 404
TENANT_NOT_FOUND; bad credentials -> 401INVALID_CREDENTIALS(no detail about which part was wrong). - When the tenant enforces device binding and another device is bound, login still succeeds; bootstrap reports
CONFLICT. - Rate limited per login and per device.
Error codes. INVALID_CREDENTIALS, TENANT_NOT_FOUND, DEVICE_BLOCKED, VERSION_TOO_OLD, RATE_LIMITED
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 LoginRequest.
{
"login": "user.a@@ap.gov",
"tenant": "ap.gov",
"password": "example-password",
"deviceId": "6b1f2c3d-0000-4000-8000-000000053249"
}| Field | Type | Required | Rules | Meaning |
|---|---|---|---|---|
login | string | Yes | pattern ^\S+$; min length 1; max length 200 | Lower-cased and trimmed. Accepted shapes: `email`, `login@@tenant`, numeric IE login. |
tenant | string | No | min length 1; max length 100 | Tenant (organisation) name; optional when `login` already contains `@@tenant`. Urvi serves `ap.gov`. |
password | string (password) | Yes | min length 1; max length 200 | Never stored on the device. |
deviceId | string (uuid) | Yes | App-scoped device UUID (not ANDROID_ID). Must equal `X-Device-Id`. | |
integrityToken | string | No | Optional Play Integrity token. |
Responses
200 Logged in.
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 Invalid credentials.
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/invalid-credentials",
"title": "Login failed",
"status": 401,
"detail": "User id or password is incorrect.",
"code": "INVALID_CREDENTIALS",
"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"
}404 Unknown tenant.
Schema Problem.
{
"type": "https://urvi.example.invalid/problems/tenant-not-found",
"title": "Organisation not found",
"status": 404,
"detail": "Organisation name not recognised.",
"code": "TENANT_NOT_FOUND",
"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"
}