Skip to main content

Overview

Harbor Parking API uses Bearer token authentication with JWT (JSON Web Tokens) issued by Supabase Auth. All API endpoints require authentication except for public documentation.

Authentication Flow

1

User Registration

Users sign up through the Harbor Parking web interface with email and apartment details.
2

Email Verification

Users must verify their email address before proceeding.
3

Admin Approval

Building administrators review and approve new users for security.
4

Token Acquisition

Approved users can obtain JWT tokens through login or direct API authentication.

Getting a JWT Token

Method 1: Web Application Login

The easiest way to get a token for testing:
  1. Visit Harbor Parking Login
  2. Sign up and get admin approval
  3. Log in and extract the token from:
    • Browser Developer Tools → Application → Local Storage
    • Network tab during API requests
    • Browser console: localStorage.getItem('supabase.auth.token')

Method 2: Direct API Authentication

curl -X POST "https://YOUR_SUPABASE_URL/auth/v1/token?grant_type=password" \
  -H "apikey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "your.email@example.com",
    "password": "your_password"
  }'

Using Your Token

Include the JWT token in the Authorization header for all API requests:
Authorization: Bearer YOUR_JWT_TOKEN
curl -X GET "https://harbor-parking.vercel.app/api/profile" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json"

Token Properties

JWT tokens contain user information and permissions:
{
  "aud": "authenticated",
  "exp": 1640995200,
  "sub": "123e4567-e89b-12d3-a456-426614174000",
  "email": "john.doe@example.com",
  "role": "authenticated",
  "app_metadata": {
    "provider": "email"
  },
  "user_metadata": {
    "email": "john.doe@example.com"
  }
}
Key Fields:
  • sub - User ID (UUID)
  • email - User’s email address
  • exp - Token expiration (Unix timestamp)
  • aud - Audience (“authenticated”)

Token Expiration

JWT tokens expire after 1 hour for security. Handle expiration gracefully:
function isTokenExpired(token) {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]));
    return Date.now() >= payload.exp * 1000;
  } catch {
    return true;
  }
}

async function makeAuthenticatedRequest(url, options = {}) {
  let token = getStoredToken();
  
  if (isTokenExpired(token)) {
    // Refresh token
    const { data } = await supabase.auth.refreshSession();
    token = data.session?.access_token;
    storeToken(token);
  }
  
  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`
    }
  });
}

Permission Levels

Different user roles have varying API access:

Regular User (Approved)

{
  "is_approved": true,
  "is_admin": false
}
API Access:
  • ✅ Profile management
  • ✅ Own parking spots CRUD
  • ✅ Create availabilities for owned spots
  • ✅ View all available spots
  • ✅ Create and manage own claims
  • ❌ Admin endpoints

Building Admin

{
  "is_approved": true,
  "is_admin": true
}
API Access:
  • ✅ All regular user permissions
  • ✅ User approval/rejection
  • ✅ Verify parking spot ownership
  • ✅ View all claims in building
  • ✅ Access admin dashboard
  • ❌ Multi-building management

Unapproved User

{
  "is_approved": false,
  "is_admin": false
}
API Access:
  • ✅ View own profile only
  • ❌ All other endpoints return 403

Security Best Practices

Never expose JWT tokens in client-side code, URLs, or logs. Treat them like passwords.

Client-Side Security

  • Secure Storage: Use httpOnly cookies or secure storage APIs
  • HTTPS Only: Never send tokens over HTTP in production
  • Token Rotation: Implement automatic token refresh
  • Logout Cleanup: Clear tokens on user logout
  • Scope Validation: Check user permissions before UI actions

Server-Side Validation

  • Verify Signature: Validate token signature with Supabase public key
  • Check Expiration: Reject expired tokens
  • Validate Claims: Verify audience, issuer, and custom claims
  • Rate Limiting: Implement per-user rate limits
  • Audit Logging: Log authentication events

Common Authentication Errors

{
  "error": "Authentication required"
}
Cause: No Authorization header provided
Solution: Include Authorization: Bearer YOUR_TOKEN
{
  "error": "Invalid token"
}
Cause: Token is malformed, expired, or revoked
Solution: Refresh token or re-authenticate
{
  "error": "Account pending approval. Contact your building administrator."
}
Cause: Valid token but user not approved
Solution: Wait for admin approval
{
  "error": "You do not have permission to perform this action"
}
Cause: User lacks required role for endpoint
Solution: Check if admin permissions needed

Testing Authentication

Test Tokens

For development, you can create test users:
# Create test user via Supabase CLI
supabase auth signup --email test@example.com --password TestPassword123!

# Get auth token for testing
supabase auth token

Postman Setup

  1. Create Environment Variables:
    • base_url: https://harbor-parking.vercel.app/api
    • jwt_token: Your JWT token
  2. Set Authorization Header:
    • Type: Bearer Token
    • Token: {{jwt_token}}
  3. Pre-request Script (for auto-refresh):
    // Check if token is expired and refresh if needed
    const token = pm.environment.get("jwt_token");
    
    if (isTokenExpired(token)) {
        // Implement token refresh logic
        refreshToken();
    }
    

cURL Examples

# Store token in variable
export HARBOR_TOKEN="your-jwt-token-here"

# Test authenticated request
curl -H "Authorization: Bearer $HARBOR_TOKEN" \
     https://harbor-parking.vercel.app/api/profile

# Test with invalid token (should return 401)
curl -H "Authorization: Bearer invalid-token" \
     https://harbor-parking.vercel.app/api/profile

Next Steps