REST API Reference
For teams not using Next.js, VibeLogin provides a complete REST API. All SDK functionality is available via HTTP endpoints. This reference covers every endpoint you need to integrate VibeLogin into any backend or client.
Base URL
https://api.vibelogin.comAuthentication
VibeLogin uses two types of API keys. Which key you use depends on whether the request originates from the client or server.
| Key Type | Header | Use Case |
|---|---|---|
| Publishable Key | x-publishable-key: pk_live_xxx | Client-side requests (signup, signin forms) |
| Secret Key | Authorization: Bearer sk_live_xxx | Server-side requests (token exchange, user management) |
Keep your secret key safe
Never expose your secret key in client-side code or public repositories. The secret key should only be used in server-side requests.
Hosted Auth Endpoints
These are the public-facing endpoints that power VibeLogin's hosted login flow. They use your project's slug in the URL path. No secret key is required — the project is identified by the slug.
All hosted auth endpoints return a one-time authorization code on success. Your backend exchanges this code for tokens using the POST /v1/auth/oauth/token endpoint with your secret key.
POST /:slug/signup
Register a new user with email and password. Returns a one-time auth code on success. If the email already exists, returns a generic success message for anti-enumeration protection.
Request Body
{
"email": "user@example.com",
"password": "securepassword123",
"name": "Jane Doe",
"metadata": { "plan": "pro" },
"redirectUrl": "https://yourapp.com/auth/callback"
}| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Valid email address | |
| password | string | Yes | Minimum 8 characters |
| name | string | No | Display name (max 255 chars) |
| metadata | object | No | Arbitrary JSON metadata |
| redirectUrl | string | Yes | Must be in your project's allowed redirect URLs |
Response 201
{ "code": "vl_code_abc123..." }Example
curl -X POST https://api.vibelogin.com/hosted/my-app/signup \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123",
"name": "Jane Doe",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/signin
Sign in with email and password. Returns a one-time auth code on success. Uses generic error messages for anti-enumeration protection.
Request Body
{
"email": "user@example.com",
"password": "securepassword123",
"redirectUrl": "https://yourapp.com/auth/callback"
}| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Valid email address | |
| password | string | Yes | User password |
| redirectUrl | string | Yes | Must be in your project's allowed redirect URLs |
Response 200
{ "code": "vl_code_abc123..." }Example
curl -X POST https://api.vibelogin.com/hosted/my-app/signin \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/magic-link
Send a magic link to the user's email address. The link expires after 15 minutes. Always returns a generic success message regardless of whether the email exists (anti-enumeration).
Request Body
{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}Response 200
{
"message": "If an account exists with this email, a magic link has been sent."
}Example
curl -X POST https://api.vibelogin.com/hosted/my-app/magic-link \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/magic-link/verify
Verify a magic link token and receive a one-time auth code. The token is single-use and expires after 15 minutes.
Request Body
{
"token": "vl_tok_abc123...",
"redirectUrl": "https://yourapp.com/auth/callback"
}Response 200
{ "code": "vl_code_abc123..." }Example
curl -X POST https://api.vibelogin.com/hosted/my-app/magic-link/verify \
-H "Content-Type: application/json" \
-d '{
"token": "vl_tok_abc123...",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/password/reset-request
Request a password reset email. The reset link expires after 15 minutes. Always returns a generic success message regardless of whether the email exists (anti-enumeration).
Request Body
{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}Response 200
{
"message": "If an account exists, a password reset link has been sent."
}Example
curl -X POST https://api.vibelogin.com/hosted/my-app/password/reset-request \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/password/reset
Complete a password reset using the token from the reset email. Sets the new password and returns a one-time auth code so the user is automatically signed in.
Request Body
{
"token": "vl_tok_reset123...",
"password": "newsecurepassword456",
"redirectUrl": "https://yourapp.com/auth/callback"
}| Field | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | Token from the password reset email |
| password | string | Yes | New password (minimum 8 characters) |
| redirectUrl | string | Yes | Must be in your project's allowed redirect URLs |
Response 200
{ "code": "vl_code_abc123..." }Example
curl -X POST https://api.vibelogin.com/hosted/my-app/password/reset \
-H "Content-Type: application/json" \
-d '{
"token": "vl_tok_reset123...",
"password": "newsecurepassword456",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/email/request-verify
Request an email verification link. The verification token expires after 24 hours. Returns a generic message regardless of whether the email exists.
Request Body
{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}Response 200
{
"message": "If an account exists, a verification email has been sent."
}Example
curl -X POST https://api.vibelogin.com/hosted/my-app/email/request-verify \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"redirectUrl": "https://yourapp.com/auth/callback"
}'POST /:slug/email/verify
Verify an email address using the token from the verification email. Marks the user's email as verified.
Request Body
{
"token": "vl_tok_verify123..."
}Response 200
{ "message": "Email verified successfully." }Example
curl -X POST https://api.vibelogin.com/hosted/my-app/email/verify \
-H "Content-Type: application/json" \
-d '{ "token": "vl_tok_verify123..." }'Token Exchange
After a successful signup, signin, or magic link verification, your backend must exchange the one-time authorization code for access and refresh tokens. This is the critical step for non-SDK integrations.
POST /v1/auth/oauth/token
Exchange a one-time authorization code for access and refresh tokens. This endpoint requires your secret key. The code is single-use and expires after a short window.
Server-side only
This endpoint requires your secret key. Call it from your backend, never from the browser.
Request Body
{
"code": "vl_code_abc123..."
}Response 200
{
"accessToken": "eyJhbGciOiJFZERTQSIs...",
"refreshToken": "vl_rt_abc123...",
"isNewUser": false
}| Field | Type | Description |
|---|---|---|
| accessToken | string | JWT access token (default 15 min expiry) |
| refreshToken | string | Opaque refresh token (default 7 day expiry) |
| isNewUser | boolean | Whether the user was just created (useful for onboarding flows) |
Example
curl -X POST https://api.vibelogin.com/v1/auth/oauth/token \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_your_secret_key" \
-d '{ "code": "vl_code_abc123..." }'Full authentication flow
1. User submits credentials to POST /:slug/signin and receives a one-time code.
2. Your frontend redirects to your callback URL with the code as a query parameter.
3. Your backend calls POST /v1/auth/oauth/token with the code and your secret key.
4. Store the tokens — set the access token as a cookie and save the refresh token server-side.
POST /v1/auth/refresh
Exchange a refresh token for a new access token and refresh token pair. The old refresh token is invalidated (rotation). Requires your secret key.
Request Body
{
"refreshToken": "vl_rt_abc123..."
}Response 200
{
"accessToken": "eyJhbGciOiJFZERTQSIs...",
"refreshToken": "vl_rt_newtoken456..."
}Example
curl -X POST https://api.vibelogin.com/v1/auth/refresh \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk_live_your_secret_key" \
-d '{ "refreshToken": "vl_rt_abc123..." }'JWKS Endpoint
GET /v1/jwks/:projectId
Returns the project's public keys in standard JWKS format (RFC 7517). Use this endpoint to configure your JWT verification library so it can validate access tokens locally without calling the API on every request. No authentication required.
This is how the VibeLogin SDK validates tokens — it fetches the JWKS once and caches it. Your backend can do the same with any JWT library that supports JWKS endpoints.
Response 200
{
"keys": [
{
"kty": "OKP",
"crv": "Ed25519",
"x": "base64url-encoded-public-key",
"kid": "key-id-uuid",
"use": "sig",
"alg": "EdDSA"
}
]
}Example
curl https://api.vibelogin.com/v1/jwks/your-project-uuidCaching
The response includes Cache-Control: public, max-age=3600 so your JWT library can cache the keys for up to 1 hour. This means token verification adds zero latency after the initial fetch.
Error Responses
All errors follow a consistent format with an error message and machine-readable error code:
{
"error": "Invalid email or password.",
"code": "INVALID_CREDENTIALS"
}| Status | Meaning | Example Code |
|---|---|---|
| 400 | Bad request (validation error, invalid token) | VALIDATION_ERROR, INVALID_TOKEN |
| 401 | Unauthorized (invalid credentials, missing auth) | INVALID_CREDENTIALS |
| 403 | Forbidden (banned user, expired token) | ACCOUNT_BANNED |
| 404 | Not found (invalid slug, project not found) | INVALID_REQUEST |
| 409 | Conflict (duplicate email) | DUPLICATE_EMAIL |
| 429 | Rate limited | RATE_LIMITED |
| 503 | Service unavailable (email delivery failed) | EMAIL_FAILED |
Rate Limits
Rate limits are applied per IP address to prevent abuse. If you exceed a limit, the API returns 429 Too Many Requests.
| Endpoint Category | Limit | Window |
|---|---|---|
| Auth (signup, signin) | 10 requests | 15 minutes per IP |
| Email (magic-link, password reset, verify) | 5 requests | 15 minutes per IP |
| Token refresh | 30 requests | 15 minutes per IP |
Handling rate limits
Rate limits are per-IP. If you hit a limit, wait and retry. The response includes a Retry-After header indicating how many seconds to wait before retrying.