Security Architecture

VibeLogin handles authentication so you don't have to think about security details. This page explains how things work under the hood for teams that want to understand the design before adopting it.

Password hashing

Passwords are hashed with Argon2id, the winner of the Password Hashing Competition and the current OWASP recommendation.

AlgorithmArgon2id
Memory cost19 MiB
Iterations2
Parallelism1
Output length32 bytes (256 bits)

Verification uses constant-time comparison to prevent timing attacks. Raw passwords are never logged or stored.

Token model

VibeLogin uses a short-lived access token + long-lived refresh token model. Both are JWTs.

Access token lifetime15 minutes (configurable)
Refresh token lifetime7 days (configurable)
Signing algorithmRS256 (RSA-2048 + SHA-256)
Key isolationEach project gets its own RSA key pair
Token refreshSilent, automatic via SDK middleware

Access token claims

{
  "sub": "user-uuid",        // User ID
  "sid": "session-uuid",     // Session ID (revocation handle)
  "jti": "token-uuid",       // Unique token ID
  "role": "member",          // User role at issuance time
  "iss": "https://api.vibelogin.com",
  "aud": "project-id",       // Prevents cross-project reuse
  "iat": 1712000000,
  "exp": 1712000900
}

The payload is intentionally minimal — no PII like email or name. This keeps tokens small and avoids leaking user data through CDN logs or browser storage.

Session management

Each login creates a server-side session record linked to the user. The refresh token is the session handle.

  • Refresh tokens are one-time use. Every refresh rotates the token and invalidates the old one.
  • Only the SHA-256 hash of the refresh token is stored. A database breach does not expose valid tokens.
  • IP address and User-Agent are captured at session creation for anomaly detection.
  • Session revocation is instant — deleting the session record invalidates all tokens for that session.

Cookie security

The SDK stores tokens in cookies, not localStorage. This protects against XSS attacks.

httpOnlytrue — JavaScript cannot read tokens
securetrue in production (HTTPS only)
sameSitelax — prevents CSRF on cross-origin POST
path/ (root-scoped)
domainConfigurable for subdomain sharing

Cookie names

  • {prefix}-access — short-lived access token
  • {prefix}-refresh — long-lived refresh token
  • vibelogin_state — OAuth/login CSRF state (10-minute TTL)

Encryption at rest

Project signing keys (RSA private keys) are encrypted before storage using AES-256-GCM.

AlgorithmAES-256-GCM
IV96-bit, randomly generated per encryption
Auth tag128-bit (integrity verification)
Key derivationHKDF-SHA256 with purpose-specific context

Each encryption context (e.g. signing key storage) derives a unique key from the master secret, so a compromise in one context doesn't affect others.

JWKS and key verification

Each project exposes a public JWKS endpoint that the SDK uses to verify access tokens without calling the VibeLogin API on every request.

GET https://api.vibelogin.com/v1/jwks/{projectId}
  • Public keys are cached for 1 hour (server and SDK)
  • Key ID (kid) in the JWT header maps to the correct key
  • Audience (aud) claim prevents cross-project token reuse

CSRF protection

The OAuth and redirect login flows use a state parameter to prevent CSRF attacks.

  • A cryptographically random state value is generated for each login
  • The state is stored in a short-lived cookie (10-minute TTL)
  • On callback, the state from the URL must match the cookie value
  • State is single-use — deleted immediately after validation

For embedded mode API calls, the SDK includes automatic CSRF token handling.

Rate limiting

All authentication endpoints are rate-limited per IP address to prevent brute-force and abuse.

EndpointLimitWindow
Sign in / Sign up10 requests15 minutes
Magic link / Password reset5 requests15 minutes
Token refresh30 requests15 minutes

Rate-limited responses return standard 429 status with Retry-After, X-RateLimit-Limit, and X-RateLimit-Remaining headers.

Security headers

The VibeLogin API sets these headers on every response:

Strict-Transport-Securitymax-age=31536000; includeSubDomains
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policycamera=(), microphone=(), geolocation=()

Anti-enumeration

Auth endpoints are designed to prevent user enumeration:

  • Signup performs a dummy Argon2 hash for existing emails so the response time is identical whether the account exists or not.
  • Error messages use generic language that does not reveal whether an email is registered.
  • Rate limiting is per-IP, not per-email, to prevent enumeration through error responses.

Redirect vs embedded security

The two integration modes have different security profiles:

  • Redirect mode: Login happens on VibeLogin's hosted pages. Your app never touches passwords. Tokens are delivered via a server-side callback. This is the more secure option.
  • Embedded mode: Login forms render in your app. Passwords are sent directly from your frontend to the VibeLogin API over HTTPS. CSRF protection is automatic via the SDK.

We recommend redirect mode for production apps. It supports the full feature set and keeps credentials off your domain entirely.