API Authentication
The CPR backend uses Laravel Sanctum for token-based API authentication.
Authentication Flow
1. POST /api/v1/auth/login → Receive Bearer token
2. Include token in all requests → Authorization: Bearer <token>
3. POST /api/v1/auth/logout → Revoke tokenLogin
http
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "password"
}Response (200):
json
{
"message": "Login successful",
"data": {
"user": {
"id": 1,
"name": "Admin User",
"email": "admin@cpr.local",
"username": "admin",
"default_branch_id": 1
},
"token": "1|abc123def456...",
"branches": [
{ "id": 1, "name": "Main Clinic", "code": "MAIN" }
]
}
}Error (401):
json
{
"message": "Invalid credentials"
}INFO
Login uses username (not email) for authentication.
Using the Token
Include the token in all subsequent requests:
http
GET /api/v1/patients
Authorization: Bearer 1|abc123def456...
X-Branch-Id: 1
Accept: application/jsonLogout
http
POST /api/v1/auth/logout
Authorization: Bearer 1|abc123def456...Revokes the current token.
Profile
http
GET /api/v1/auth/profile
Authorization: Bearer 1|abc123def456...http
PUT /api/v1/auth/profile
Authorization: Bearer 1|abc123def456...
{
"name": "Updated Name",
"email": "newemail@example.com"
}Branch Switching
http
POST /api/v1/auth/switch-branch
Authorization: Bearer 1|abc123def456...
{
"branch_id": 2
}Updates the user's active branch context.
http
GET /api/v1/auth/branches
Authorization: Bearer 1|abc123def456...Returns all branches the user has access to.
Password Reset
The password reset uses a code-based flow (not link-based):
Step 1: Request Reset Code
http
POST /api/v1/auth/reset-code
{ "email": "user@example.com" }Sends a numeric code to the user's email.
Step 2: Verify Code
http
POST /api/v1/auth/verify-code
{ "email": "user@example.com", "code": "123456" }Step 3: Reset Password
http
POST /api/v1/auth/reset-password
{
"email": "user@example.com",
"code": "123456",
"password": "newpassword",
"password_confirmation": "newpassword"
}Change Password (Authenticated)
http
POST /api/v1/profile/change-password
Authorization: Bearer 1|abc123def456...
{
"current_password": "oldpassword",
"password": "newpassword",
"password_confirmation": "newpassword"
}Token Configuration
| Setting | Value |
|---|---|
| Token type | Sanctum (opaque) |
| Default expiration | None (configurable via API_TOKEN_EXPIRY) |
| Storage | personal_access_tokens table |
Rate Limiting
Authentication endpoints have stricter rate limits:
| Endpoint | Limit |
|---|---|
POST /auth/login | 5 requests / minute per IP |
| All other auth routes | 5 requests / minute per IP |
| General API | 1000 requests / minute per user |
Testing Auth with cURL
bash
# Login
TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}' | jq -r '.data.token')
# Use the token
curl http://localhost:8000/api/v1/patients \
-H "Authorization: Bearer $TOKEN" \
-H "X-Branch-Id: 1" \
-H "Accept: application/json"