Authentication API
Base path: /api/v1/auth
Implementation reference: internal/handlers/auth.go, models in internal/models/auth.go.
Endpoints
| Method | Path | Description | Auth Required |
|---|---|---|---|
| POST | /auth/register | Register a new user | No |
| POST | /auth/login | Log in and receive tokens | No |
| POST | /auth/refresh | Refresh an expired access token | No |
| POST | /auth/logout | Invalidate current session | Yes |
| GET | /auth/me | Get current user profile | Yes |
| POST | /auth/change-password | Change authenticated user's password | Yes |
| POST | /auth/password-reset-request | Request a password reset email | No |
| POST | /auth/password-reset-confirm | Complete password reset with token | No |
POST /auth/register
Creates a new user account and returns JWT tokens. Optionally creates a new organization.
Request:
{
"email": "user@example.com",
"name": "John Doe",
"password": "securePassword123",
"organization_name": "My Org"
}Response (201 Created):
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
"token_type": "Bearer",
"expires_at": "2026-06-11T22:30:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"organization_id": 1
}
}POST /auth/login
Authenticates with email and password. Returns JWT tokens valid for 8 hours. The refresh token is valid for 30 days.
Request:
{
"email": "user@example.com",
"password": "securePassword123"
}Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
"token_type": "Bearer",
"expires_at": "2026-06-11T22:30:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"organization_id": 1
}
}Failed login attempts are logged to the login_attempts table for security auditing (see internal/handlers/auth.go:514).
POST /auth/refresh
Exchange a valid refresh token for a new access/refresh token pair.
Request:
{
"refresh_token": "dGhpcyBpcyBhIHJlZnJl..."
}Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "bmV3IHJlZnJlc2ggdG9r...",
"token_type": "Bearer",
"expires_at": "2026-06-11T23:00:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"organization_id": 1
}
}POST /auth/logout
Invalidates the current session by deleting the session record from user_sessions. Requires the Authorization header.
Response (200 OK):
{
"message": "Logged out successfully"
}GET /auth/me
Returns the authenticated user's profile. Reads user_id from the JWT context injected by the auth middleware (internal/middleware/auth.go:25).
Response (200 OK):
{
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"organization_id": 1
}POST /auth/change-password
Changes the current user's password. Requires the current password for verification.
Request:
{
"current_password": "securePassword123",
"new_password": "newSecurePassword456"
}Response (200 OK):
{
"message": "Password changed successfully"
}POST /auth/password-reset-request
Initiates the password reset flow. Generates a UUID token valid for 1 hour and stores it in password_reset_tokens. Always returns success (even if the email doesn't exist) to prevent email enumeration.
Request:
{
"email": "user@example.com"
}Response (200 OK):
{
"message": "If the email exists, a reset link has been sent"
}POST /auth/password-reset-confirm
Completes the password reset by providing the token received via email and a new password. Marks the token as used to prevent replay.
Request:
{
"token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"new_password": "newSecurePassword456"
}Response (200 OK):
{
"message": "Password reset successfully"
}Error Codes
| HTTP Status | Scenario |
|---|---|
400 | Invalid request body (malformed JSON, missing fields) |
401 | Invalid credentials, expired/ invalid token |
404 | User not found (on /auth/me, /auth/refresh) |
500 | Password hashing failure, database error |