Users - Authentication
Location: api/nextango/apps/users/authentication.py
Last Updated: 2026-07-08
Overview
PIN-based login for POS terminals, plus token refresh and logout. Email/password login and registration live in the Web Auth domain; this page covers the endpoints and serializer that are users-owned. Token authentication itself is implemented by CustomTokenAuthentication (see Backends).
The app's URLconf is mounted at users/auth/ in the project URL configuration, so every path below carries that prefix. Each endpoint is also registered a second time under an additional auth/ segment inside the app (for example /users/auth/auth/pin-login/); the shorter form is canonical. The absolute /auth/... prefix without the users/ segment belongs to the Web Auth domain and does not serve these endpoints.
POST /users/auth/pin-login/
Also registered at /users/auth/auth/pin-login/.
Auth required: none (AllowAny)
Request:
{
"employee_id": "EMP-001",
"pin_code": "1234",
"store_id": "store-uuid-or-sanity-id",
"terminal_id": "optional-terminal-identifier"
}
Response (200):
{
"success": true,
"token": "auth_token",
"user": {
"id": "uuid",
"employee_id": "EMP-001",
"employee_uuid": "employee-row-uuid",
"email": "[email protected]",
"name": "Jane Doe",
"status": "active",
"role": "employee",
"roles": ["employee"],
"permissions": [],
"store_id": "store-uuid",
"store_sanity_id": "store-sanity-id",
"store_name": "Downtown",
"store_code": "DT01"
},
"employee": {
"id": "employee-row-uuid",
"employee_id": "EMP-001",
"role_type": "employee",
"hourly_rate": "15.00"
}
}
employee_uuid is the Employee (or Manager) row's primary key, distinct from user.id; it is the identifier POS transaction creation links against. permissions is populated only when the caller is a manager, from Manager.override_permissions.
Response (400): {"success": false, "message": "<error>"}, carrying the first validation error from PINLoginSerializer or a generic invalid-credentials message.
Validation performed by PINLoginSerializer
- Resolves
store_idagainstStoreby either UUID or Sanity ID; fails with "Invalid store selection" if no store matches. - Resolves
employee_idagainstEmployeefirst, thenManager, requiring the owning user'sstatus == 'active'; fails with "Invalid employee ID or PIN" if neither matches (the same message as a PIN mismatch, so the response does not reveal whether the employee ID exists). - Compares the submitted PIN against the stored
pin_code; fails the same way on mismatch or on a record with no PIN set. - Checks store assignment: a manager row with an empty
store_assignmentsarray is treated as having unrestricted access; otherwise the store must appear instore_assignments, matched viastore_ref_matches()with an additional database fallback that resolves an assignment reference throughStorebefore comparing.
POST /users/auth/refresh/
Also registered at /users/auth/auth/validate/.
Auth required: token (CustomTokenAuthentication)
Validates the caller's existing token and returns the current user summary. Does not issue a new token; the same token is returned.
Response (200):
{
"token": "auth_token",
"user": {
"id": "uuid",
"email": "[email protected]",
"name": "Jane Doe",
"status": "active",
"roles": ["employee"],
"primary_role": "employee"
},
"valid": true
}
POST /users/auth/logout/
Also registered at /users/auth/auth/logout/.
Auth required: token (CustomTokenAuthentication)
Deletes the caller's DRF token. Responds 200 with {"message": "Successfully logged out"} on success, or 400 with {"message": "No active session found"} if the caller has no token to delete.
Related Documentation
- Backends:
CustomTokenAuthentication, the status-active gate on every token request - Permissions:
store_ref_matches(), the shared store-reference comparison - Models:
Employee.pin_code,Manager.store_assignments - Web Auth Views: email/password login and registration