Skip to main content

Overview

Strike Auth Service uses JWT (JSON Web Tokens) for authentication, providing a secure and stateless way to authenticate users. The service supports multiple authentication methods and follows OAuth 2.0 standards where applicable.

Authentication Flow

1

User Registration/Login

Users can register or login using various methods (email/password, magic links, OAuth, etc.)
2

Token Issuance

Upon successful authentication, the service issues an access token and refresh token
3

API Requests

Include the access token in the Authorization header for authenticated requests
4

Token Refresh

Use the refresh token to obtain new access tokens when they expire

Token Types

Access Token

  • Purpose: Authenticate API requests
  • Lifetime: 1 hour (3600 seconds)
  • Format: JWT with user claims
  • Usage: Include in Authorization: Bearer <token> header

Refresh Token

  • Purpose: Obtain new access tokens
  • Lifetime: 30 days (configurable)
  • Format: Opaque string
  • Usage: Send to /token endpoint with grant_type=refresh_token

Service Role Key

  • Purpose: Admin operations and server-to-server communication
  • Lifetime: No expiration (until rotated)
  • Format: Opaque string
  • Usage: Include in Authorization: Bearer <service-role-key> header

Authentication Methods

  • Email & Password
  • OTP (SMS)
  • OAuth
  • Admin Login
Traditional authentication with email and password.
curl -X POST "http://localhost:8080/token?grant_type=password" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "securepassword123"
  }'

Security Headers

All authenticated requests should include the access token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Rate Limiting

Authentication endpoints include rate limiting to prevent abuse:
HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetTime until window resets (seconds)

Error Handling

Authentication errors follow a consistent format:
{
  "code": 401,
  "msg": "Invalid credentials",
  "details": "Email or password is incorrect"
}
Common authentication error codes:
CodeDescription
400Bad Request - Invalid request format
401Unauthorized - Invalid or missing credentials
403Forbidden - Insufficient permissions
429Too Many Requests - Rate limit exceeded

JWT Token Structure

Access tokens are JWTs containing user information:
{
  "aud": "authenticated",
  "exp": 1640995200,
  "iat": 1640908800,
  "iss": "https://your-project.supabase.co/auth/v1",
  "sub": "123e4567-e89b-12d3-a456-426614174000",
  "email": "user@example.com",
  "phone": "+1234567890",
  "app_metadata": {
    "provider": "email",
    "providers": ["email"]
  },
  "user_metadata": {},
  "role": "authenticated"
}

Best Practices

  • Store access tokens in memory or secure storage
  • Store refresh tokens in secure, httpOnly cookies when possible
  • Never store tokens in localStorage in production
  • Implement automatic token refresh before expiration - Handle refresh token rotation properly - Implement proper error handling for expired refresh tokens
  • Always use HTTPS in production - Implement proper CORS policies - Validate tokens on every request - Log authentication events for security monitoring
  • Handle authentication errors gracefully
  • Implement proper logout on token expiration
  • Provide clear error messages to users

Example Implementation

Here’s a complete example of implementing authentication in JavaScript:
class AuthService {
  constructor(baseUrl) {
    this.baseUrl = baseUrl;
    this.accessToken = null;
    this.refreshToken = null;
  }

  async login(email, password) {
    const response = await fetch(`${this.baseUrl}/token?grant_type=password`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, password }),
    });

    if (!response.ok) {
      throw new Error("Login failed");
    }

    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token;

    return data.user;
  }

  async refreshAccessToken() {
    if (!this.refreshToken) {
      throw new Error("No refresh token available");
    }

    const response = await fetch(
      `${this.baseUrl}/token?grant_type=refresh_token`,
      {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ refresh_token: this.refreshToken }),
      }
    );

    if (!response.ok) {
      throw new Error("Token refresh failed");
    }

    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token;
  }

  async makeAuthenticatedRequest(url, options = {}) {
    const headers = {
      Authorization: `Bearer ${this.accessToken}`,
      "Content-Type": "application/json",
      ...options.headers,
    };

    let response = await fetch(url, { ...options, headers });

    // If token expired, try to refresh
    if (response.status === 401) {
      await this.refreshAccessToken();
      headers["Authorization"] = `Bearer ${this.accessToken}`;
      response = await fetch(url, { ...options, headers });
    }

    return response;
  }

  logout() {
    this.accessToken = null;
    this.refreshToken = null;
  }
}

Next Steps

I