Authentication - arilonUK/iotagentmesh GitHub Wiki

Authentication API

The Authentication API provides secure access control for the IoT Agent Mesh platform using JWT-based authentication with row-level security (RLS) and multi-tenant organization isolation.

Overview

The authentication system provides:

  • JWT-based authentication with automatic token refresh
  • Row-level security (RLS) for data isolation between organizations
  • Role-based access control (RBAC) within organizations
  • Session management and logout functionality
  • Password reset and email verification
  • API key management for programmatic access

Base Endpoint

/auth/v1/

Authentication Flow

Standard Authentication Flow

sequenceDiagram
    participant Client
    participant Auth API
    participant Database
    participant Application API
Client->>Auth API: Sign In Request
Auth API->>Database: Validate Credentials
Database->>Auth API: User Data + Organization
Auth API->>Client: JWT Token + User Profile

Client->>Application API: API Request (with JWT)
Application API->>Database: Query with RLS
Database->>Application API: Filtered Results
Application API->>Client: Response

Authentication Endpoints

Sign In with Email and Password

Authenticate a user with email and password credentials.

POST /auth/v1/token?grant_type=password

Request Headers

Content-Type: application/json
apikey: YOUR_SUPABASE_ANON_KEY

Request Body

{
  "email": "[email protected]",
  "password": "secure-password"
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721750400,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "aud": "authenticated",
    "role": "authenticated",
    "email": "[email protected]",
    "email_confirmed_at": "2024-01-15T10:30:00Z",
    "phone": null,
    "confirmed_at": "2024-01-15T10:30:00Z",
    "last_sign_in_at": "2024-07-23T16:45:00Z",
    "app_metadata": {
      "provider": "email",
      "providers": ["email"]
    },
    "user_metadata": {
      "organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
      "organization_role": "admin",
      "full_name": "John Doe",
      "avatar_url": "https://example.com/avatar.jpg"
    },
    "identities": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "user_id": "550e8400-e29b-41d4-a716-446655440000",
        "identity_data": {
          "email": "[email protected]",
          "sub": "550e8400-e29b-41d4-a716-446655440000"
        },
        "provider": "email",
        "last_sign_in_at": "2024-07-23T16:45:00Z",
        "created_at": "2024-01-15T10:30:00Z",
        "updated_at": "2024-07-23T16:45:00Z"
      }
    ],
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-07-23T16:45:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient( 'https://your-project-id.supabase.co', 'your-anon-key' )

const { data, error } = await supabase.auth.signInWithPassword({ email: '[email protected]', password: 'secure-password' })

if (error) throw error

console.log('User:', data.user) console.log('Session:', data.session)

// The JWT token is now automatically included in all API requests const { data: organizations } = await supabase .from('organizations') .select('*')

Python:

from supabase import create_client

supabase = create_client( "https://your-project-id.supabase.co", "your-anon-key" )

response = supabase.auth.sign_in_with_password({ "email": "[email protected]", "password": "secure-password" })

user = response.user session = response.session

cURL:

curl -X POST \
  "https://your-project-id.supabase.co/auth/v1/token?grant_type=password" \
  -H "apikey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "secure-password"
  }'

Sign Up

Create a new user account.

POST /auth/v1/signup

Request Body

{
  "email": "[email protected]",
  "password": "secure-password",
  "data": {
    "full_name": "Jane Smith",
    "organization_name": "Tech Innovations Inc",
    "phone": "+1-555-0123"
  }
}

Response

{
  "access_token": null,
  "token_type": "bearer",
  "expires_in": null,
  "expires_at": null,
  "refresh_token": null,
  "user": {
    "id": "7f3e8b2a-1d45-4c8e-9a7b-2e5f8c9d0a1b",
    "aud": "authenticated",
    "role": "authenticated",
    "email": "[email protected]",
    "email_confirmed_at": null,
    "confirmation_sent_at": "2024-07-23T17:00:00Z",
    "app_metadata": {
      "provider": "email",
      "providers": ["email"]
    },
    "user_metadata": {
      "full_name": "Jane Smith",
      "organization_name": "Tech Innovations Inc",
      "phone": "+1-555-0123"
    },
    "created_at": "2024-07-23T17:00:00Z",
    "updated_at": "2024-07-23T17:00:00Z"
  }
}

Note: Email confirmation is required before the user can sign in.

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.signUp({
  email: '[email protected]',
  password: 'secure-password',
  options: {
    data: {
      full_name: 'Jane Smith',
      organization_name: 'Tech Innovations Inc',
      phone: '+1-555-0123'
    }
  }
})

if (error) throw error console.log('User created:', data.user) console.log('Check email for confirmation link')


Refresh Token

Refresh an expired JWT token using a refresh token.

POST /auth/v1/token?grant_type=refresh_token

Request Body

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "last_sign_in_at": "2024-07-23T17:00:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.refreshSession()

if (error) throw error console.log('Token refreshed:', data.session)


Sign Out

Invalidate the current session and sign out the user.

POST /auth/v1/logout

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY

Response

{
  "message": "Successfully logged out"
}

Code Examples

JavaScript/TypeScript:

const { error } = await supabase.auth.signOut()

if (error) throw error console.log('User signed out successfully')


Password Management

Reset Password Request

Request a password reset email for a user.

POST /auth/v1/recover

Request Body

{
  "email": "[email protected]"
}

Response

{
  "message": "Password recovery email sent"
}

Code Examples

JavaScript/TypeScript:

const { error } = await supabase.auth.resetPasswordForEmail(
  '[email protected]',
  {
    redirectTo: 'https://yourapp.com/reset-password'
  }
)

if (error) throw error console.log('Password reset email sent')


Update Password

Update the user's password (requires authentication).

PUT /auth/v1/user

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Request Body

{
  "password": "new-secure-password"
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "updated_at": "2024-07-23T17:15:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.updateUser({
  password: 'new-secure-password'
})

if (error) throw error console.log('Password updated successfully')


User Profile Management

Get User Profile

Retrieve the current user's profile information.

GET /auth/v1/user

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "aud": "authenticated",
  "role": "authenticated",
  "email": "[email protected]",
  "email_confirmed_at": "2024-01-15T10:30:00Z",
  "phone": "+1-555-0123",
  "phone_confirmed_at": "2024-01-15T10:35:00Z",
  "confirmed_at": "2024-01-15T10:30:00Z",
  "last_sign_in_at": "2024-07-23T16:45:00Z",
  "app_metadata": {
    "provider": "email",
    "providers": ["email"]
  },
  "user_metadata": {
    "organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
    "organization_role": "admin",
    "full_name": "John Doe",
    "avatar_url": "https://example.com/avatar.jpg",
    "timezone": "America/New_York",
    "preferences": {
      "email_notifications": true,
      "sms_notifications": false,
      "dashboard_theme": "dark"
    }
  },
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-07-23T16:45:00Z"
}

Code Examples

JavaScript/TypeScript:

const { data: { user }, error } = await supabase.auth.getUser()

if (error) throw error console.log('Current user:', user)


Update User Profile

Update the current user's profile metadata.

PUT /auth/v1/user

Request Body

{
  "data": {
    "full_name": "John Smith",
    "avatar_url": "https://example.com/new-avatar.jpg",
    "timezone": "America/Los_Angeles",
    "preferences": {
      "email_notifications": true,
      "sms_notifications": true,
      "dashboard_theme": "light"
    }
  }
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "user_metadata": {
      "full_name": "John Smith",
      "avatar_url": "https://example.com/new-avatar.jpg",
      "timezone": "America/Los_Angeles",
      "preferences": {
        "email_notifications": true,
        "sms_notifications": true,
        "dashboard_theme": "light"
      }
    },
    "updated_at": "2024-07-23T17:20:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.updateUser({
  data: {
    full_name: 'John Smith',
    timezone: 'America/Los_Angeles',
    preferences: {
      email_notifications: true,
      sms_notifications: true,
      dashboard_theme: 'light'
    }
  }
})

if (error) throw error console.log('Profile updated:', data.user)


API Key Management

Generate API Key

Create a new API key for programmatic access.

POST /functions/v1/generate-api-key

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Request Body

{
  "name": "Production Integration",
  "description": "API key for production telemetry ingestion",
  "permissions": ["telemetry:write", "agents:read"],
  "expires_in_days": 365
}

Response

{
  "api_key": "sk_live_01H8K3L4M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8",
  "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
  "name": "Production Integration",
  "description": "API key for production telemetry ingestion",
  "permissions": ["telemetry:write", "agents:read"],
  "created_at": "2024-07-23T17:25:00Z",
  "expires_at": "2025-07-23T17:25:00Z",
  "last_used": null
}

Code Examples

JavaScript/TypeScript:

const response = await supabase.functions.invoke('generate-api-key', {
  body: {
    name: 'Production Integration',
    description: 'API key for production telemetry ingestion',
    permissions: ['telemetry:write', 'agents:read'],
    expires_in_days: 365
  }
})

console.log('API Key:', response.data.api_key)


List API Keys

Retrieve all API keys for the current user.

GET /functions/v1/api-keys

Response

{
  "api_keys": [
    {
      "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
      "name": "Production Integration",
      "description": "API key for production telemetry ingestion",
      "permissions": ["telemetry:write", "agents:read"],
      "created_at": "2024-07-23T17:25:00Z",
      "expires_at": "2025-07-23T17:25:00Z",
      "last_used": "2024-07-23T16:45:00Z",
      "usage_count": 125000,
      "status": "active"
    },
    {
      "key_id": "key_02H8K3L4M5N6O7P8Q9R0S1T2U3V5",
      "name": "Development Testing",
      "description": "API key for development environment",
      "permissions": ["*"],
      "created_at": "2024-06-15T10:00:00Z",
      "expires_at": "2024-12-15T10:00:00Z",
      "last_used": "2024-07-22T14:30:00Z",
      "usage_count": 5420,
      "status": "active"
    }
  ]
}

Revoke API Key

Revoke an existing API key.

DELETE /functions/v1/api-keys/{key_id}

Response

{
  "message": "API key revoked successfully",
  "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
  "revoked_at": "2024-07-23T17:30:00Z"
}

Using API Keys

API Key Authentication

Use API keys for server-to-server authentication instead of JWT tokens.

Request Headers

Authorization: Bearer YOUR_API_KEY
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Example Request

curl -X POST \
  "https://your-project-id.supabase.co/rest/v1/telemetry" \
  -H "Authorization: Bearer sk_live_01H8K3L4M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8" \
  -H "apikey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent_123",
    "data": {
      "temperature": 23.5,
      "humidity": 65.2
    }
  }'

Code Examples

JavaScript/TypeScript:

// Create a Supabase client with API key authentication
const supabaseWithApiKey = createClient(
  'https://your-project-id.supabase.co',
  'your-anon-key',
  {
    global: {
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    }
  }
)

// Use the client for API requests const { data, error } = await supabaseWithApiKey .from('telemetry') .insert({ agent_id: 'agent_123', data: { temperature: 23.5, humidity: 65.2 } })


Row Level Security (RLS)

Understanding RLS

Row Level Security automatically filters data based on the authenticated user's organization membership. This ensures complete data isolation between organizations.

RLS Policy Examples

-- Organizations: Users can only access their own organization
CREATE POLICY "org_access" ON organizations
  FOR ALL USING (
    id IN (
      SELECT organization_id 
      FROM users 
      WHERE id = auth.uid()
    )
  );

-- Agents: Organization-scoped access CREATE POLICY "agent_access" ON agents FOR ALL USING ( organization_id IN ( SELECT organization_id FROM users WHERE id = auth.uid() ) );

-- Telemetry: Access through agent ownership CREATE POLICY "telemetry_access" ON telemetry FOR ALL USING ( agent_id IN ( SELECT a.id FROM agents a JOIN users u ON a.organization_id = u.organization_id WHERE u.id = auth.uid() ) );

Role-Based Access Control

Additional access control based on user roles within organizations:

-- Admin-only access to user management
CREATE POLICY "admin_user_management" ON users
  FOR ALL USING (
    organization_id IN (
      SELECT organization_id 
      FROM users 
      WHERE id = auth.uid() 
      AND role = 'admin'
    )
  );

-- Read-only access for viewer role CREATE POLICY "viewer_read_only" ON telemetry FOR SELECT USING ( agent_id IN ( SELECT a.id FROM agents a JOIN users u ON a.organization_id = u.organization_id WHERE u.id = auth.uid() AND u.role IN ('admin', 'user', 'viewer') ) );


Session Management

Session Handling

The authentication system automatically manages sessions:

  • Access tokens expire after 1 hour
  • Refresh tokens are valid for 30 days
  • Automatic refresh happens when access token expires
  • Session persistence across browser sessions

JavaScript Session Management

// Listen for auth state changes
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_IN') {
    console.log('User signed in:', session.user)
    // Redirect to dashboard or update UI
  } else if (event === 'SIGNED_OUT') {
    console.log('User signed out')
    // Redirect to login or clear user data
  } else if (event === 'TOKEN_REFRESHED') {
    console.log('Token refreshed:', session)
    // Token automatically refreshed
  }
})

// Get current session const { data: { session } } = await supabase.auth.getSession() if (session) { console.log('User is authenticated:', session.user) } else { console.log('User is not authenticated') }


Error Responses

Common Error Codes

HTTP Code Error Code Description
400 INVALID_CREDENTIALS Invalid email or password
400 SIGNUP_DISABLED User registration is disabled
400 WEAK_PASSWORD Password doesn't meet requirements
401 UNAUTHORIZED Missing or invalid authentication
403 EMAIL_NOT_CONFIRMED Email address not confirmed
403 USER_DISABLED User account has been disabled
422 EMAIL_ALREADY_EXISTS Email address already registered
429 RATE_LIMIT_EXCEEDED Too many authentication attempts

Rate limits are per IP address and apply globally across all organizations.

# Authentication API

The Authentication API provides secure access control for the IoT Agent Mesh platform using JWT-based authentication with row-level security (RLS) and multi-tenant organization isolation.

Overview

The authentication system provides:

  • JWT-based authentication with automatic token refresh
  • Row-level security (RLS) for data isolation between organizations
  • Role-based access control (RBAC) within organizations
  • Session management and logout functionality
  • Password reset and email verification
  • API key management for programmatic access

Base Endpoint

/auth/v1/

Authentication Flow

Standard Authentication Flow

sequenceDiagram
    participant Client
    participant Auth API
    participant Database
    participant Application API
    
    Client->>Auth API: Sign In Request
    Auth API->>Database: Validate Credentials
    Database->>Auth API: User Data + Organization
    Auth API->>Client: JWT Token + User Profile
    
    Client->>Application API: API Request (with JWT)
    Application API->>Database: Query with RLS
    Database->>Application API: Filtered Results
    Application API->>Client: Response
Loading

Authentication Endpoints

Sign In with Email and Password

Authenticate a user with email and password credentials.

POST /auth/v1/token?grant_type=password

Request Headers

Content-Type: application/json
apikey: YOUR_SUPABASE_ANON_KEY

Request Body

{
  "email": "[email protected]",
  "password": "secure-password"
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721750400,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "aud": "authenticated",
    "role": "authenticated",
    "email": "[email protected]",
    "email_confirmed_at": "2024-01-15T10:30:00Z",
    "phone": null,
    "confirmed_at": "2024-01-15T10:30:00Z",
    "last_sign_in_at": "2024-07-23T16:45:00Z",
    "app_metadata": {
      "provider": "email",
      "providers": ["email"]
    },
    "user_metadata": {
      "organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
      "organization_role": "admin",
      "full_name": "John Doe",
      "avatar_url": "https://example.com/avatar.jpg"
    },
    "identities": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "user_id": "550e8400-e29b-41d4-a716-446655440000",
        "identity_data": {
          "email": "[email protected]",
          "sub": "550e8400-e29b-41d4-a716-446655440000"
        },
        "provider": "email",
        "last_sign_in_at": "2024-07-23T16:45:00Z",
        "created_at": "2024-01-15T10:30:00Z",
        "updated_at": "2024-07-23T16:45:00Z"
      }
    ],
    "created_at": "2024-01-15T10:30:00Z",
    "updated_at": "2024-07-23T16:45:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

import { createClient } from '@supabase/supabase-js'

const supabase = createClient(
  'https://your-project-id.supabase.co',
  'your-anon-key'
)

const { data, error } = await supabase.auth.signInWithPassword({
  email: '[email protected]',
  password: 'secure-password'
})

if (error) throw error

console.log('User:', data.user)
console.log('Session:', data.session)

// The JWT token is now automatically included in all API requests
const { data: organizations } = await supabase
  .from('organizations')
  .select('*')

Python:

from supabase import create_client

supabase = create_client(
    "https://your-project-id.supabase.co",
    "your-anon-key"
)

response = supabase.auth.sign_in_with_password({
    "email": "[email protected]",
    "password": "secure-password"
})

user = response.user
session = response.session

cURL:

curl -X POST \
  "https://your-project-id.supabase.co/auth/v1/token?grant_type=password" \
  -H "apikey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "secure-password"
  }'

Sign Up

Create a new user account.

POST /auth/v1/signup

Request Body

{
  "email": "[email protected]",
  "password": "secure-password",
  "data": {
    "full_name": "Jane Smith",
    "organization_name": "Tech Innovations Inc",
    "phone": "+1-555-0123"
  }
}

Response

{
  "access_token": null,
  "token_type": "bearer",
  "expires_in": null,
  "expires_at": null,
  "refresh_token": null,
  "user": {
    "id": "7f3e8b2a-1d45-4c8e-9a7b-2e5f8c9d0a1b",
    "aud": "authenticated",
    "role": "authenticated",
    "email": "[email protected]",
    "email_confirmed_at": null,
    "confirmation_sent_at": "2024-07-23T17:00:00Z",
    "app_metadata": {
      "provider": "email",
      "providers": ["email"]
    },
    "user_metadata": {
      "full_name": "Jane Smith",
      "organization_name": "Tech Innovations Inc",
      "phone": "+1-555-0123"
    },
    "created_at": "2024-07-23T17:00:00Z",
    "updated_at": "2024-07-23T17:00:00Z"
  }
}

Note: Email confirmation is required before the user can sign in.

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.signUp({
  email: '[email protected]',
  password: 'secure-password',
  options: {
    data: {
      full_name: 'Jane Smith',
      organization_name: 'Tech Innovations Inc',
      phone: '+1-555-0123'
    }
  }
})

if (error) throw error
console.log('User created:', data.user)
console.log('Check email for confirmation link')

Refresh Token

Refresh an expired JWT token using a refresh token.

POST /auth/v1/token?grant_type=refresh_token

Request Body

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "last_sign_in_at": "2024-07-23T17:00:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.refreshSession()

if (error) throw error
console.log('Token refreshed:', data.session)

Sign Out

Invalidate the current session and sign out the user.

POST /auth/v1/logout

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY

Response

{
  "message": "Successfully logged out"
}

Code Examples

JavaScript/TypeScript:

const { error } = await supabase.auth.signOut()

if (error) throw error
console.log('User signed out successfully')

Password Management

Reset Password Request

Request a password reset email for a user.

POST /auth/v1/recover

Request Body

{
  "email": "[email protected]"
}

Response

{
  "message": "Password recovery email sent"
}

Code Examples

JavaScript/TypeScript:

const { error } = await supabase.auth.resetPasswordForEmail(
  '[email protected]',
  {
    redirectTo: 'https://yourapp.com/reset-password'
  }
)

if (error) throw error
console.log('Password reset email sent')

Update Password

Update the user's password (requires authentication).

PUT /auth/v1/user

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Request Body

{
  "password": "new-secure-password"
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "updated_at": "2024-07-23T17:15:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.updateUser({
  password: 'new-secure-password'
})

if (error) throw error
console.log('Password updated successfully')

User Profile Management

Get User Profile

Retrieve the current user's profile information.

GET /auth/v1/user

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY

Response

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "aud": "authenticated",
  "role": "authenticated",
  "email": "[email protected]",
  "email_confirmed_at": "2024-01-15T10:30:00Z",
  "phone": "+1-555-0123",
  "phone_confirmed_at": "2024-01-15T10:35:00Z",
  "confirmed_at": "2024-01-15T10:30:00Z",
  "last_sign_in_at": "2024-07-23T16:45:00Z",
  "app_metadata": {
    "provider": "email",
    "providers": ["email"]
  },
  "user_metadata": {
    "organization_id": "org_01H8K2M3N4P5Q6R7S8T9U0V1W2",
    "organization_role": "admin",
    "full_name": "John Doe",
    "avatar_url": "https://example.com/avatar.jpg",
    "timezone": "America/New_York",
    "preferences": {
      "email_notifications": true,
      "sms_notifications": false,
      "dashboard_theme": "dark"
    }
  },
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-07-23T16:45:00Z"
}

Code Examples

JavaScript/TypeScript:

const { data: { user }, error } = await supabase.auth.getUser()

if (error) throw error
console.log('Current user:', user)

Update User Profile

Update the current user's profile metadata.

PUT /auth/v1/user

Request Body

{
  "data": {
    "full_name": "John Smith",
    "avatar_url": "https://example.com/new-avatar.jpg",
    "timezone": "America/Los_Angeles",
    "preferences": {
      "email_notifications": true,
      "sms_notifications": true,
      "dashboard_theme": "light"
    }
  }
}

Response

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "expires_at": 1721754000,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "user_metadata": {
      "full_name": "John Smith",
      "avatar_url": "https://example.com/new-avatar.jpg",
      "timezone": "America/Los_Angeles",
      "preferences": {
        "email_notifications": true,
        "sms_notifications": true,
        "dashboard_theme": "light"
      }
    },
    "updated_at": "2024-07-23T17:20:00Z"
  }
}

Code Examples

JavaScript/TypeScript:

const { data, error } = await supabase.auth.updateUser({
  data: {
    full_name: 'John Smith',
    timezone: 'America/Los_Angeles',
    preferences: {
      email_notifications: true,
      sms_notifications: true,
      dashboard_theme: 'light'
    }
  }
})

if (error) throw error
console.log('Profile updated:', data.user)

API Key Management

Generate API Key

Create a new API key for programmatic access.

POST /functions/v1/generate-api-key

Request Headers

Authorization: Bearer YOUR_JWT_TOKEN
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Request Body

{
  "name": "Production Integration",
  "description": "API key for production telemetry ingestion",
  "permissions": ["telemetry:write", "agents:read"],
  "expires_in_days": 365
}

Response

{
  "api_key": "sk_live_01H8K3L4M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8",
  "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
  "name": "Production Integration",
  "description": "API key for production telemetry ingestion",
  "permissions": ["telemetry:write", "agents:read"],
  "created_at": "2024-07-23T17:25:00Z",
  "expires_at": "2025-07-23T17:25:00Z",
  "last_used": null
}

Code Examples

JavaScript/TypeScript:

const response = await supabase.functions.invoke('generate-api-key', {
  body: {
    name: 'Production Integration',
    description: 'API key for production telemetry ingestion',
    permissions: ['telemetry:write', 'agents:read'],
    expires_in_days: 365
  }
})

console.log('API Key:', response.data.api_key)

List API Keys

Retrieve all API keys for the current user.

GET /functions/v1/api-keys

Response

{
  "api_keys": [
    {
      "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
      "name": "Production Integration",
      "description": "API key for production telemetry ingestion",
      "permissions": ["telemetry:write", "agents:read"],
      "created_at": "2024-07-23T17:25:00Z",
      "expires_at": "2025-07-23T17:25:00Z",
      "last_used": "2024-07-23T16:45:00Z",
      "usage_count": 125000,
      "status": "active"
    },
    {
      "key_id": "key_02H8K3L4M5N6O7P8Q9R0S1T2U3V5",
      "name": "Development Testing",
      "description": "API key for development environment",
      "permissions": ["*"],
      "created_at": "2024-06-15T10:00:00Z",
      "expires_at": "2024-12-15T10:00:00Z",
      "last_used": "2024-07-22T14:30:00Z",
      "usage_count": 5420,
      "status": "active"
    }
  ]
}

Revoke API Key

Revoke an existing API key.

DELETE /functions/v1/api-keys/{key_id}

Response

{
  "message": "API key revoked successfully",
  "key_id": "key_01H8K3L4M5N6O7P8Q9R0S1T2U3V4",
  "revoked_at": "2024-07-23T17:30:00Z"
}

Using API Keys

API Key Authentication

Use API keys for server-to-server authentication instead of JWT tokens.

Request Headers

Authorization: Bearer YOUR_API_KEY
apikey: YOUR_SUPABASE_ANON_KEY
Content-Type: application/json

Example Request

curl -X POST \
  "https://your-project-id.supabase.co/rest/v1/telemetry" \
  -H "Authorization: Bearer sk_live_01H8K3L4M5N6O7P8Q9R0S1T2U3V4W5X6Y7Z8" \
  -H "apikey: YOUR_SUPABASE_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agent_123",
    "data": {
      "temperature": 23.5,
      "humidity": 65.2
    }
  }'

Code Examples

JavaScript/TypeScript:

// Create a Supabase client with API key authentication
const supabaseWithApiKey = createClient(
  'https://your-project-id.supabase.co',
  'your-anon-key',
  {
    global: {
      headers: {
        'Authorization': `Bearer ${API_KEY}`
      }
    }
  }
)

// Use the client for API requests
const { data, error } = await supabaseWithApiKey
  .from('telemetry')
  .insert({
    agent_id: 'agent_123',
    data: { temperature: 23.5, humidity: 65.2 }
  })

Row Level Security (RLS)

Understanding RLS

Row Level Security automatically filters data based on the authenticated user's organization membership. This ensures complete data isolation between organizations.

RLS Policy Examples

-- Organizations: Users can only access their own organization
CREATE POLICY "org_access" ON organizations
  FOR ALL USING (
    id IN (
      SELECT organization_id 
      FROM users 
      WHERE id = auth.uid()
    )
  );

-- Agents: Organization-scoped access
CREATE POLICY "agent_access" ON agents
  FOR ALL USING (
    organization_id IN (
      SELECT organization_id 
      FROM users 
      WHERE id = auth.uid()
    )
  );

-- Telemetry: Access through agent ownership
CREATE POLICY "telemetry_access" ON telemetry
  FOR ALL USING (
    agent_id IN (
      SELECT a.id 
      FROM agents a
      JOIN users u ON a.organization_id = u.organization_id
      WHERE u.id = auth.uid()
    )
  );

Role-Based Access Control

Additional access control based on user roles within organizations:

-- Admin-only access to user management
CREATE POLICY "admin_user_management" ON users
  FOR ALL USING (
    organization_id IN (
      SELECT organization_id 
      FROM users 
      WHERE id = auth.uid() 
      AND role = 'admin'
    )
  );

-- Read-only access for viewer role
CREATE POLICY "viewer_read_only" ON telemetry
  FOR SELECT USING (
    agent_id IN (
      SELECT a.id 
      FROM agents a
      JOIN users u ON a.organization_id = u.organization_id
      WHERE u.id = auth.uid()
      AND u.role IN ('admin', 'user', 'viewer')
    )
  );

Session Management

Session Handling

The authentication system automatically manages sessions:

  • Access tokens expire after 1 hour
  • Refresh tokens are valid for 30 days
  • Automatic refresh happens when access token expires
  • Session persistence across browser sessions

JavaScript Session Management

// Listen for auth state changes
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_IN') {
    console.log('User signed in:', session.user)
    // Redirect to dashboard or update UI
  } else if (event === 'SIGNED_OUT') {
    console.log('User signed out')
    // Redirect to login or clear user data
  } else if (event === 'TOKEN_REFRESHED') {
    console.log('Token refreshed:', session)
    // Token automatically refreshed
  }
})

// Get current session
const { data: { session } } = await supabase.auth.getSession()
if (session) {
  console.log('User is authenticated:', session.user)
} else {
  console.log('User is not authenticated')
}

Error Responses

Common Error Codes

HTTP Code Error Code Description
400 INVALID_CREDENTIALS Invalid email or password
400 SIGNUP_DISABLED User registration is disabled
400 WEAK_PASSWORD Password doesn't meet requirements
401 UNAUTHORIZED Missing or invalid authentication
403 EMAIL_NOT_CONFIRMED Email address not confirmed
403 USER_DISABLED User account has been disabled
422 EMAIL_ALREADY_EXISTS Email address already registered
429 RATE_LIMIT_EXCEEDED Too many authentication attempts

Example Error Response

{
  "error": {
    "code": "INVALID_CREDENTIALS",
    "message": "Invalid email or password",
    "details": {
      "field": "password",
      "reason": "Password does not match"
    }
  },
  "status": 400
}

Security Best Practices

Password Requirements

  • Minimum 8 characters
  • At least one uppercase letter
  • At least one lowercase letter
  • At least one number
  • At least one special character

API Key Security

  1. Key Rotation: Rotate API keys regularly (recommended: every 90 days)
  2. Principle of Least Privilege: Grant minimal required permissions
  3. Secure Storage: Never expose API keys in client-side code
  4. Monitoring: Monitor API key usage for suspicious activity

Session Security

  1. HTTPS Only: Always use HTTPS in production
  2. Secure Cookies: Enable secure cookie settings
  3. Session Timeout: Implement appropriate session timeouts
  4. Device Tracking: Monitor sign-ins from new devices

Related Resources

  • [Organizations API](API-Organizations.md) - Organization management
  • [Users API](API-Users.md) - User management within organizations
  • [Rate Limiting](API-Rate-Limiting.md) - API rate limiting policies
  • [Error Handling](API-Error-Handling.md) - Error handling best practices

Rate Limits

Operation Rate Limit Window
Sign In 10 requests 1 minute
Sign Up 5 requests 1 minute
Password Reset 3 requests 1 minute
Token Refresh 20 requests 1 minute
Profile Update 10 requests 1 minute
API Key Generation 2 requests 1 hour

Rate limits are per IP address and apply globally across all organizations.

⚠️ **GitHub.com Fallback** ⚠️