Skip to content

Authentication API

Base path: /api/v1/auth

Implementation reference: internal/handlers/auth.go, models in internal/models/auth.go.

Endpoints

MethodPathDescriptionAuth Required
POST/auth/registerRegister a new userNo
POST/auth/loginLog in and receive tokensNo
POST/auth/refreshRefresh an expired access tokenNo
POST/auth/logoutInvalidate current sessionYes
GET/auth/meGet current user profileYes
POST/auth/change-passwordChange authenticated user's passwordYes
POST/auth/password-reset-requestRequest a password reset emailNo
POST/auth/password-reset-confirmComplete password reset with tokenNo

POST /auth/register

Creates a new user account and returns JWT tokens. Optionally creates a new organization.

Request:

json
{
  "email": "user@example.com",
  "name": "John Doe",
  "password": "securePassword123",
  "organization_name": "My Org"
}

Response (201 Created):

json
{
  "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:

json
{
  "email": "user@example.com",
  "password": "securePassword123"
}

Response (200 OK):

json
{
  "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:

json
{
  "refresh_token": "dGhpcyBpcyBhIHJlZnJl..."
}

Response (200 OK):

json
{
  "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):

json
{
  "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):

json
{
  "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:

json
{
  "current_password": "securePassword123",
  "new_password": "newSecurePassword456"
}

Response (200 OK):

json
{
  "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:

json
{
  "email": "user@example.com"
}

Response (200 OK):

json
{
  "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:

json
{
  "token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "new_password": "newSecurePassword456"
}

Response (200 OK):

json
{
  "message": "Password reset successfully"
}

Error Codes

HTTP StatusScenario
400Invalid request body (malformed JSON, missing fields)
401Invalid credentials, expired/ invalid token
404User not found (on /auth/me, /auth/refresh)
500Password hashing failure, database error