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

  1. Resolves store_id against Store by either UUID or Sanity ID; fails with "Invalid store selection" if no store matches.
  2. Resolves employee_id against Employee first, then Manager, requiring the owning user's status == '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).
  3. Compares the submitted PIN against the stored pin_code; fails the same way on mismatch or on a record with no PIN set.
  4. Checks store assignment: a manager row with an empty store_assignments array is treated as having unrestricted access; otherwise the store must appear in store_assignments, matched via store_ref_matches() with an additional database fallback that resolves an assignment reference through Store before 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.

  • 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

Was this page helpful?