Skip to content

Authentication

All endpoints are prefixed with /v1. Honeycomb supports two authentication methods: Bearer tokens (JWT via Supabase Auth) and API keys.

Used for user sessions. Obtained via sign-in or token refresh. Include the token in the Authorization header:

Authorization: Bearer <access_token>

Tokens are standard Supabase Auth JWTs. They expire based on the expires_in value returned at sign-in. Use the refresh endpoint to obtain a new token pair before expiry.

Used for scripts, integrations, and server-to-server communication. Include the key in the X-API-Key header:

X-API-Key: <api_key>

API keys are SHA-256 hashed before storage in the api_keys table. The plaintext key is only shown once at creation time.


The API uses a layered middleware system for authentication and authorization:

MiddlewareBehavior
authenticate()Runs on every request. Non-blocking. Populates req.user if a valid token or API key is present.
requireAuthBlocks the request with 401 Unauthorized if req.user is not set.
requireAdminBlocks the request with 403 Forbidden if req.user.role is not admin.
apiKeyAuthStrict gate that accepts either X-API-Key or Authorization: Bearer. Returns 401 if neither is valid.

When authentication succeeds, req.user is populated with:

interface ReqUser {
id: string; // UUID
email: string;
role: string; // e.g. "user", "admin"
type?: string; // account type
status?: string; // account status
username?: string;
}

POST /v1/auth/sign-up

Register a new user account. No authentication required.

Request Body:

FieldTypeRequiredConstraintsDescription
emailstringYesValid email formatUser’s email address
passwordstringYesMin 8 charactersAccount password
first_namestringNoUser’s first name
last_namestringNoUser’s last name

Response 201 Created:

{
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "jane@example.com"
}
}

Error Responses:

StatusBodyCondition
400{ "error": "Validation error", "details": [...] }Invalid email or short password
409{ "error": "Email already registered" }Duplicate email address

POST /v1/auth/sign-in

Authenticate with email and password. Returns access and refresh tokens along with user info.

Request Body:

FieldTypeRequiredDescription
emailstringYesUser’s email
passwordstringYesAccount password

Response 200 OK:

{
"session": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "v1.MjA0ZDFhYmUtYTdk...",
"expires_in": 3600,
"expires_at": 1711843200
},
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "jane@example.com",
"role": "user"
}
}
Response FieldTypeDescription
session.access_tokenstringJWT for authenticating subsequent requests
session.refresh_tokenstringToken used to obtain a new access token
session.expires_innumberToken lifetime in seconds
session.expires_atnumberUnix timestamp when the access token expires
user.idstringUser UUID
user.emailstringUser’s email
user.rolestringUser’s role (e.g. "user", "admin")

Error Responses:

StatusBodyCondition
401{ "error": "Invalid credentials" }Wrong email or password

POST /v1/auth/sign-out

Invalidates the current session. Requires authentication.

Headers:

HeaderValueRequired
AuthorizationBearer <access_token>Yes

Request Body: None

Response 200 OK:

{
"message": "Signed out"
}

Error Responses:

StatusBodyCondition
401{ "error": "Not authenticated" }Missing or invalid token

POST /v1/auth/forgot-password

Sends a password reset link to the given email address. No authentication required.

Request Body:

FieldTypeRequiredConstraintsDescription
emailstringYesValid email formatAccount email address

Response 200 OK:

{
"message": "If the email exists, a reset link has been sent"
}

POST /v1/auth/reset-password

Resets the user’s password using the recovery token from the password reset email. Requires authentication — the recovery token from the email must be passed as a Bearer token.

Headers:

HeaderValueRequired
AuthorizationBearer <recovery_token>Yes

Request Body:

FieldTypeRequiredConstraintsDescription
passwordstringYesMin 8 charactersNew password

Response 200 OK:

{
"message": "Password reset successful"
}

Error Responses:

StatusBodyCondition
400{ "error": "Missing password" }password field not provided
401{ "error": "Authentication required — pass the recovery token as Bearer" }Missing or invalid recovery token

POST /v1/auth/verify-email

Verifies a user’s email address using the token hash from the verification email.

Request Body:

FieldTypeRequiredConstraintsDescription
token_hashstringYesToken hash from the verification email
typestringYesEnum: "email"Verification type

Response 200 OK:

{
"session": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "v1.MjA0ZDFhYmUtYTdk...",
"expires_in": 3600
},
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "jane@example.com"
}
}

Error Responses:

StatusBodyCondition
400{ "error": "token_hash and type are required" }Missing required fields
400{ "error": "Invalid token" }Expired or malformed token hash

POST /v1/auth/resend-verification

Resends the email verification link. No authentication required.

Request Body:

FieldTypeRequiredConstraintsDescription
emailstringYesValid email formatEmail address to verify

Response 200 OK:

{
"message": "Verification email resent"
}

Error Responses:

StatusBodyCondition
400{ "error": "Email is required" }email not provided

POST /v1/auth/refresh

Exchange a valid refresh token for a new access/refresh token pair. No authentication header required — the refresh token is passed in the body.

Request Body:

FieldTypeRequiredDescription
refresh_tokenstringYesRefresh token from a previous sign-in

Response 200 OK:

{
"session": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "v1.NTY3ZjlkMmEtMGRi...",
"expires_in": 3600,
"expires_at": 1711846800
}
}

Error Responses:

StatusBodyCondition
401{ "error": "Invalid or expired refresh token" }Token is expired, revoked, or invalid

GET /v1/auth/session

Returns the currently authenticated user’s session information. Requires authentication.

Headers:

HeaderValueRequired
AuthorizationBearer <access_token>Yes

Query Parameters: None

Request Body: None

Response 200 OK:

{
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "jane@example.com",
"role": "user",
"type": "creator",
"status": "active",
"username": "janedoe"
}
}
Response FieldTypeNullableDescription
user.idstringNoUser UUID
user.emailstringNoUser’s email address
user.rolestringNoUser’s role (e.g. "user", "admin")
user.typestringYesAccount type
user.statusstringYesAccount status (e.g. "active")
user.usernamestringYesUsername, if set

Error Responses:

StatusBodyCondition
401{ "error": "Not authenticated" }Missing or invalid token

Terminal window
# 1. Sign up
curl -X POST https://api.honeycomb.example/v1/auth/sign-up \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "secureP@ss1",
"first_name": "Jane",
"last_name": "Doe"
}'
# 2. Sign in (after email verification)
curl -X POST https://api.honeycomb.example/v1/auth/sign-in \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "secureP@ss1"
}'
# 3. Use access token for authenticated requests
curl https://api.honeycomb.example/v1/auth/session \
-H "Authorization: Bearer eyJhbGciOi..."
# 4. Refresh when token is about to expire
curl -X POST https://api.honeycomb.example/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{ "refresh_token": "v1.MjA0ZDFh..." }'
# 5. Sign out
curl -X POST https://api.honeycomb.example/v1/auth/sign-out \
-H "Authorization: Bearer eyJhbGciOi..."