Skip to main content

Authentication

The YBH Pulse Content API uses JWT (JSON Web Token) authentication with HTTP-only cookies for secure session management.

Authentication Flow

  1. Login - Exchange email/password for JWT token
  2. Session - Token stored in secure HTTP-only cookie
  3. Requests - Cookie automatically included in subsequent requests
  4. Logout - Clear cookie to end session

Login

Authenticate and receive a session cookie.
curl -X POST https://production.youvebeenheard.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "your_password"
  }'

Request

email
string
required
User email address (must be @youvebeenheard.com domain)
password
string
required
User password

Response

user
object
Authenticated user information
The response includes a Set-Cookie header with the JWT token:
Set-Cookie: auth_token=<jwt>; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=604800

Error Responses

StatusErrorDescription
400Missing required fieldsEmail or password not provided
401Invalid credentialsEmail not found or password incorrect
429Too many attemptsRate limit exceeded (5 attempts per 15 minutes)
500Authentication failedServer error during authentication
Email Domain Restriction: Only @youvebeenheard.com email addresses are permitted. This is enforced server-side to prevent unauthorized access.

Get Current User

Retrieve information about the currently authenticated user.
curl https://production.youvebeenheard.com/api/auth/me \
  -H "Cookie: auth_token=<token>"

Response

{
  "user": {
    "_id": "user_abc123",
    "name": "John Doe",
    "email": "[email protected]",
    "role": "admin"
  }
}

Error Responses

StatusErrorDescription
401UnauthorizedNo token provided or token expired
401Session expiredToken no longer valid

Logout

End the current session by clearing the authentication cookie.
curl -X POST https://production.youvebeenheard.com/api/auth/logout \
  -H "Cookie: auth_token=<token>"

Response

{
  "success": true,
  "message": "Logged out successfully"
}
The response includes a Set-Cookie header that clears the token:
Set-Cookie: auth_token=; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=0

Forgot Password

Request a password reset email.
curl -X POST https://production.youvebeenheard.com/api/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'
email
string
required
Email address for password reset

Response

{
  "success": true,
  "message": "Password reset email sent"
}
Rate Limit: 3 password reset requests per hour per IP address.

Reset Password

Reset password using a token from the reset email.
curl -X POST https://production.youvebeenheard.com/api/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{
    "token": "<reset_token>",
    "password": "new_password"
  }'
token
string
required
Reset token from email
password
string
required
New password (minimum 8 characters)

Response

{
  "success": true,
  "message": "Password reset successfully"
}

JWT Token Structure

The JWT token contains:
{
  "userId": "user_abc123",
  "email": "[email protected]",
  "role": "admin",
  "iat": 1678901234,
  "exp": 1679506034
}
userId
string
User ID for database lookups
email
string
User email address
role
string
User role for RBAC: admin, designer, or user
iat
number
Issued at timestamp (Unix)
exp
number
Expiration timestamp (Unix) - 7 days from issuance
AttributeValueDescription
HttpOnlytruePrevents JavaScript access (XSS protection)
SecuretrueOnly sent over HTTPS (production)
SameSiteStrictCSRF protection
Path/Available site-wide
Max-Age6048007 days (1 week)
Token Expiration: JWT tokens expire after 7 days. Users must re-authenticate after expiration. The frontend should handle 401 responses and redirect to login.

Using Authentication in Requests

Once authenticated, the cookie is automatically included in all requests:
// No need to manually handle the cookie
const response = await fetch('https://production.youvebeenheard.com/api/sanity/episodes', {
  credentials: 'include' // Ensures cookie is sent
})
For programmatic API access without a browser:
// 1. Login and save cookie
const loginResponse = await fetch('/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, password })
})
const cookie = loginResponse.headers.get('set-cookie')

// 2. Use cookie in subsequent requests
const apiResponse = await fetch('/api/sanity/episodes', {
  headers: { 'Cookie': cookie }
})

User Roles

The API supports role-based access control (RBAC):
RolePermissions
adminFull access to all endpoints
designerRead/write episodes, generate content, manage images
userRead-only access to episodes
Role enforcement is implemented at the application level. The JWT token includes the user’s role for authorization checks.

Build docs developers (and LLMs) love