Authentication
The API uses three authentication models, one per audience. Each endpoint URL tells you which one applies.
Public Endpoints — No Authentication
Endpoints under /api/v1/* (without /me/ or /admin/ prefixes) are public. No token, no key, no header required. Just hit them.
curl https://your-site.com/api/v1/posts
Rate limit: 60 requests per minute per IP address.
User Authentication — Sanctum Tokens
Endpoints under /api/v1/me/* require a bearer token. Tokens are issued via POST /api/v1/auth/login (existing users) or POST /api/v1/auth/register (new accounts).
Step 1: Get a Token
For an existing user:
curl -X POST https://your-site.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "[email protected]",
"password": "your-password",
"device_name": "my-mobile-app"
}'
Response:
{
"success": true,
"message": "Logged in successfully",
"data": {
"token": "1|abc123XYZ...",
"token_type": "Bearer",
"user": {
"id": 8,
"name": "You",
"email": "[email protected]",
"email_verified": true
}
}
}
Store the token value. It's the only thing that proves who you are.
Step 2: Use the Token
Send it in the Authorization header on every subsequent request:
curl https://your-site.com/api/v1/me \
-H "Authorization: Bearer 1|abc123XYZ..." \
-H "Accept: application/json"
Step 3: Revoke When Done
curl -X POST https://your-site.com/api/v1/auth/logout \
-H "Authorization: Bearer 1|abc123XYZ..."
The token is deleted server-side. Any future request with it returns 401.
Token Abilities (Scopes)
Sanctum tokens carry abilities — fine-grained permissions that limit what the token can do. A read-only mobile token can't accidentally delete a comment.
Available Abilities
| Ability | What it allows |
|---|---|
user |
Read own profile, manage own tokens |
comments:write |
Post comments on behalf of the user |
tickets:write |
Open support tickets |
newsletter:manage |
Subscribe/unsubscribe to newsletter |
admin |
Full admin endpoints (/api/v1/admin/*) |
Issuing Scoped Tokens
When a user creates a token via POST /api/v1/me/tokens, they pick the abilities:
curl -X POST https://your-site.com/api/v1/me/tokens \
-H "Authorization: Bearer YOUR_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Read-only mobile app",
"abilities": ["user"]
}'
The default auth/login flow issues a token with just ["user"]. To get an admin-capable token, see "Admin Authentication" below.
What Happens Without the Right Ability
If a token tries to hit an endpoint that requires an ability it doesn't have, the API returns 403 Forbidden with errors.code: "FORBIDDEN". The token isn't revoked — it just can't access that specific endpoint.
Admin Authentication
Admin endpoints (/api/v1/admin/*) require a token with the admin ability. There's no /auth/login endpoint that issues admin tokens directly — this is intentional. Admin access is bootstrapped by the site owner, not granted via API.
Creating an Admin Token
On the server, in php artisan tinker:
$user = App\Models\User::where('email', '[email protected]')->first();
$token = $user->createToken('my-integration', ['admin']);
echo $token->plainTextToken;
// 6|xyz789ABC...
That token has ["admin"] ability. It can hit any /api/v1/admin/* endpoint at 30 requests/minute.
Why Not Issue Admin Tokens via API?
If /auth/login returned admin tokens automatically, anyone who phished an admin's password would get full programmatic access. By requiring explicit token creation via tinker (or the upcoming admin UI), we limit the blast radius of credential theft.
Token Expiry
By default, Sanctum tokens don't expire until revoked. This is intentional for mobile apps where you don't want users to re-login every week.
To set expiry, configure config/sanctum.php:
'expiration' => 60 * 24 * 30, // 30 days
After this, tokens older than 30 days return 401.
Rate Limits
| Endpoint group | Rate |
|---|---|
/api/v1/auth/login |
5/min per IP |
/api/v1/auth/register |
3/min per IP |
/api/v1/auth/forgot-password |
3/min per IP |
/api/v1/me/* |
120/min per user |
/api/v1/admin/* |
30/min per user |
Other /api/v1/* (public) |
60/min per IP |
Exceeded limits return 429 Too Many Requests with a Retry-After header.
Security Best Practices
- Never commit tokens to git. Store in env vars or a secrets manager.
- Use device-specific tokens. Issue one token per mobile install, web SPA, or integration. Revoke individually if compromised.
- Scope tokens to minimum abilities. A "read-only widget" token doesn't need
admin. - Rotate admin tokens periodically. Generate a fresh one, update your integration, delete the old one.
- Verify HTTPS. The API only accepts HTTPS in production. The bearer token is in the
Authorizationheader — never put it in URL query strings (those show up in logs).
Next Steps
- List own tokens —
GET /api/v1/me/tokens - Webhook signing — verify HMAC signatures on incoming events