On this page
Customer Auth
Customer authentication for storefronts built with Hydra. Customers register and log in with email and password. Hydra issues short-lived JWTs for API access and opaque refresh tokens for session continuity. This is separate from admin/merchant authentication.
Base URL: https://api.hydrajs.dev
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/v1/auth/register |
Publishable | Create customer account, return tokens |
POST |
/v1/auth/login |
Publishable | Email + password login |
POST |
/v1/auth/token |
Publishable | Refresh access token |
POST |
/v1/auth/logout |
Publishable | Invalidate refresh token |
POST |
/v1/auth/forgot-password |
Publishable | Request password reset |
POST |
/v1/auth/reset-password |
Publishable | Reset password with token |
ℹPublishable keys only
All auth endpoints require a publishable API key (pk_live_* or pk_test_*) via the X-API-Key
header. Secret keys are not needed.
⚠Prerequisite: store domain
Customer auth requires a domain to be set on the project (via PATCH /v1/store or the admin panel).
Without it, all auth endpoints return 400 with "Store domain must be configured to use customer auth.".
The domain is used for email verification links, password reset URLs, and other customer-facing emails.
See Store API — Domain verification for setup.
ℹToken strategy
Login and registration return an access token (JWT, 1 hour) and a refresh token (opaque, 30 days).
The access token is sent as a Bearer token for authenticated requests to /v1/me. Refresh tokens
are single-use with rotation — each refresh invalidates the old token and returns a new one.
Register
POST /v1/auth/register
Creates a new customer account with email and password. Returns access and refresh tokens along with the customer profile. The email must be unique within the project.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Email address (max 255 chars) |
password |
string | Yes | Password (8-128 chars, must include uppercase, lowercase, and digit) |
first_name |
string | Yes | First name (1-100 chars) |
last_name |
string | Yes | Last name (1-100 chars) |
phone |
string | No | Phone number (max 30 chars) |
locale |
string | No | Preferred language (BCP 47, max 10 chars, e.g. en, es-419). Determines email language |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/register \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "SecurePass1",
"first_name": "Jane",
"last_name": "Smith",
"phone": "+1-555-0123"
}'
Response 201
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
"expires_in": 3600,
"customer": {
"id": "cus_abc123",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone": "+1-555-0123",
"locale": null,
"email_verified": false,
"created_at": "2026-08-31T10:00:00Z",
"updated_at": "2026-08-31T10:00:00Z"
}
}
Login
POST /v1/auth/login
Authenticates a customer with email and password. Returns access and refresh tokens. Progressive lockout applies after repeated failures (5 failures: 1 min, 10: 5 min, 20+: 15 min).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Email address |
password |
string | Yes | Password |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/login \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "SecurePass1"
}'
Response 200
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJl...",
"expires_in": 3600,
"customer": {
"id": "cus_abc123",
"email": "jane@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone": "+1-555-0123",
"locale": null,
"email_verified": false,
"created_at": "2026-08-31T10:00:00Z",
"updated_at": "2026-08-31T10:00:00Z"
}
}
⚠Security
Returns 401 Unauthorized with "Invalid email or password." for both wrong email and wrong
password (prevents email enumeration). Returns 429 Too Many Requests with Retry-After header
when the account is temporarily locked.
Refresh token
POST /v1/auth/token
Exchanges a valid refresh token for new access and refresh tokens. The old refresh token is invalidated (single-use rotation). If a consumed token is submitted, all tokens in the session family are revoked as a theft countermeasure.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token |
string | Yes | The refresh token from login or a previous refresh |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/token \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "dGhpcyBpcyBhIHJlZnJl..."
}'
Response 200
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "bmV3IHJlZnJlc2ggdG9r...",
"expires_in": 3600
}
ℹNo customer object
The refresh response does not include the customer object. Use GET /v1/me to fetch the profile
if needed.
Logout
POST /v1/auth/logout
Invalidates the provided refresh token. Idempotent — returns 204 even if the token was already invalidated or does not exist.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token |
string | Yes | The refresh token to invalidate |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/logout \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "dGhpcyBpcyBhIHJlZnJl..."
}'
Response 204
No body.
Forgot password
POST /v1/auth/forgot-password
Generates a password reset token. Always returns a generic success message regardless of whether the email exists (prevents email enumeration). When the transactional email system is available, a reset link will be sent to the customer.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | Yes | Email address (max 255 chars) |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/forgot-password \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com"
}'
Response 200
{
"message": "If an account exists, a reset link has been sent."
}
Reset password
POST /v1/auth/reset-password
Validates the reset token and sets a new password. The token is single-use and expires after 24 hours. All existing sessions for the customer are invalidated.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
token |
string | Yes | The reset token from the forgot-password flow |
password |
string | Yes | New password (8-128 chars, must include uppercase, lowercase, and digit) |
Request
curl -X POST https://api.hydrajs.dev/v1/auth/reset-password \
-H "X-API-Key: pk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"token": "cmVzZXQgdG9rZW4gaGVyZQ...",
"password": "NewSecurePass1"
}'
Response 200
{
"message": "Password has been reset successfully."
}
Token response object
Returned by register, login, refresh, and change-password endpoints.
| Field | Type | Description |
|---|---|---|
access_token |
string | HS256 JWT valid for 1 hour |
refresh_token |
string | Opaque token valid for 30 days (single-use) |
expires_in |
integer | Access token TTL in seconds (3600) |
customer |
object | Customer profile (present on register and login only) |
Auth customer object
Returned inside the token response on register and login.
| Field | Type | Description |
|---|---|---|
id |
string | Customer ID (e.g. cus_abc123) |
email |
string | Email address |
first_name |
string | First name |
last_name |
string | Last name |
phone |
string|null | Phone number |
locale |
string|null | Preferred language (BCP 47, e.g. en, es-419) |
email_verified |
boolean | Whether the email has been verified |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |