Auth API
All auth endpoints are under /api/v1/auth. Rate limit: 20 requests/minute.
Endpoints
| Method | Path | Auth | Description |
|---|
| POST | /auth/register | Public | Register a new user |
| POST | /auth/login | Public | Login and get tokens |
| POST | /auth/logout | Required | Revoke refresh token |
| POST | /auth/verify-email | Public | Verify email address |
| POST | /auth/password-reset/request | Public | Request password reset email |
| POST | /auth/password-reset/confirm | Public | Set new password |
| POST | /auth/refresh | Public | Rotate access token |
| GET | /auth/google | Public | Initiate Google OAuth |
| GET | /auth/google/callback | Public | Google OAuth callback |
Register
Create a new user account. Sends a verification email.
Request Body
{
"email": "user@example.com",
"password": "Secure@123",
"first_name": "John",
"last_name": "Doe"
}
Response 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"email_verified": false,
"created_at": "2024-01-15T10:30:00Z"
}
Errors
| Status | Detail |
|---|
409 | Email already registered |
422 | Validation error (invalid email, weak password) |
Login
Authenticate and receive JWT access + refresh tokens.
Request Body
{
"email": "user@example.com",
"password": "Secure@123"
}
Response 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com",
"first_name": "John"
}
}
Token Expiry
| Token | Lifetime |
|---|
| Access token | 60 minutes |
| Refresh token | 7 days |
Errors
| Status | Detail |
|---|
401 | Invalid email or password |
403 | Email not verified |
Logout
Revoke the current refresh token (invalidates the session).
POST /auth/logout
Authorization: Bearer <access_token>
Response 200 OK
{ "message": "Logged out successfully" }
Verify Email
Confirm an email address using the token from the verification email.
Request Body
{
"token": "abc123verificationtoken"
}
Response 200 OK
{ "message": "Email verified successfully" }
Errors
| Status | Detail |
|---|
400 | Invalid or expired verification token |
Request Password Reset
Send a password reset email.
POST /auth/password-reset/request
Request Body
{
"email": "user@example.com"
}
Response 200 OK
{ "message": "Password reset email sent" }
Always returns 200 even if the email is not registered (prevents user enumeration).
Confirm Password Reset
Set a new password using the token from the reset email.
POST /auth/password-reset/confirm
Request Body
{
"token": "abc123resettoken",
"new_password": "NewSecure@456"
}
Response 200 OK
{ "message": "Password reset successfully" }
Errors
| Status | Detail |
|---|
400 | Invalid or expired reset token |
Refresh Token
Exchange a refresh token for a new access token. The refresh token is rotated on each use.
Request Body
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
Token rotation is enabled — each refresh invalidates the old refresh token and issues a new one.
Errors
| Status | Detail |
|---|
401 | Invalid or expired refresh token |
Google OAuth
Single sign-on via Google. Redirects through Google’s consent screen and returns tokens on success.
Step 1 — Initiate
Redirect the user’s browser to:
This redirects to Google’s OAuth consent screen.
Step 2 — Callback
After the user approves, Google redirects back to:
GET /api/v1/auth/google/callback?code=...
On success, the server redirects to the frontend with the access token:
/auth/callback?access_token=eyJhbGc...
The frontend (AuthCallback page) reads the token from the URL, fetches the user profile, and stores auth state.
New vs Returning Users
- New user — account is auto-created with
auth_provider = "google", no password set
- Returning user — existing account is found by email and tokens are issued
Using Tokens
Include the access token in the Authorization header for all protected endpoints:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
When the access token expires (60 min), call POST /auth/refresh to get a new one. The frontend Axios interceptor handles this automatically.