Skip to main content

Overview

The Tailscale API Edge Function provides integration with Tailscale’s network, enabling device discovery, auth key generation, enrollment validation, and device synchronization. Endpoint: /functions/v1/tailscale-api?action={action} Authentication: Required (Authorization header with Supabase JWT for most actions) Method: POST for most actions, GET for list operations

Authentication

The function uses OAuth 2.0 client credentials flow to obtain Tailscale API access tokens:

Actions

List Devices

Retrieve all devices in the Tailscale network (tailnet). Action: list-devices Authentication: Service-level only
success
boolean
Request success status
devices
TailscaleDevice[]
Array of Tailscale devices
Example
curl -X POST 'https://your-project.supabase.co/functions/v1/tailscale-api?action=list-devices' \
  -H 'Authorization: Bearer YOUR_SERVICE_KEY'

Check Device

Check if a specific device exists in the Tailscale network. Action: check-device
identifier
string
required
Device hostname, name, or IP address to search for
success
boolean
Request success
found
boolean
Whether device was found
online
boolean
Device online status (if found)
device
object
Device details (if found)
Example
curl -X POST 'https://your-project.supabase.co/functions/v1/tailscale-api?action=check-device' \
  -H 'Authorization: Bearer YOUR_SERVICE_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"identifier": "my-laptop"}'

Generate Auth Key

Generate a pre-authorized Tailscale auth key for device enrollment. Action: generate-auth-key Authentication: User-level required
deviceId
string
Device ID to associate with auth key
tags
string[]
Tailscale ACL tags to apply (default: ["tag:prod"])
group
string
Tailscale ACL group (default: "sap")
success
boolean
Whether key was generated
authKey
string
Tailscale auth key for device enrollment
expiresAt
string
Key expiration timestamp (24 hours)
Example
curl -X POST 'https://your-project.supabase.co/functions/v1/tailscale-api?action=generate-auth-key' \
  -H 'Authorization: Bearer YOUR_JWT' \
  -H 'Content-Type: application/json' \
  -d '{
    "deviceId": "uuid-of-device",
    "tags": ["tag:prod", "tag:user"],
    "group": "engineering"
  }'

Validate Enrollment

Validate that a device has successfully enrolled in Tailscale. Action: validate-enrollment Authentication: User-level required
deviceId
string
required
Device ID to validate
hostname
string
Expected hostname to match in Tailscale
success
boolean
Request success
enrolled
boolean
Whether device is enrolled and online
device
object
Tailscale device details (if enrolled)
message
string
Status message
Example
curl -X POST 'https://your-project.supabase.co/functions/v1/tailscale-api?action=validate-enrollment' \
  -H 'Authorization: Bearer YOUR_JWT' \
  -H 'Content-Type: application/json' \
  -d '{
    "deviceId": "uuid-of-device",
    "hostname": "my-laptop"
  }'

Sync Devices

Synchronize all Tailscale devices with local database. Action: sync-devices Authentication: User-level required
success
boolean
Sync success
synced
number
Number of devices synchronized
totalTailscaleDevices
number
Total devices in Tailscale network
Example
curl -X POST 'https://your-project.supabase.co/functions/v1/tailscale-api?action=sync-devices' \
  -H 'Authorization: Bearer YOUR_JWT'

TypeScript Interfaces

TypeScript
interface TailscaleDevice {
  id: string
  name: string
  hostname: string
  user: string
  ipAddresses: string[]
  lastSeen: string
  online: boolean
  os: string
  clientVersion: string
  tags?: string[]
}

interface TailscaleAuthKeyRequest {
  capabilities: {
    devices: {
      create: {
        reusable: boolean
        ephemeral: boolean
        preauthorized: boolean
        tags?: string[]
      }
    }
  }
  expirySeconds?: number
  description?: string
}

OAuth Flow

The function automatically handles OAuth token acquisition:
  1. Requests access token from https://api.tailscale.com/api/v2/oauth/token
  2. Uses client credentials grant type
  3. Caches token for subsequent requests
  4. Automatically determines tailnet from token
OAuth Request
{
  client_id: string
  client_secret: string
  grant_type: 'client_credentials'
}

Auth Key Configuration

When generating auth keys, the function:
  1. Prefers stored key: Uses TAILSCALE_AUTH_KEY environment variable if available
  2. Fallback to API: Generates new key via Tailscale API if no stored key
  3. Key properties:
    • Reusable: Yes
    • Ephemeral: No (persistent devices)
    • Pre-authorized: Yes (no manual approval needed)
    • Expiry: 24 hours

Device Metadata Updates

When devices enroll or sync, the devices table is updated with:
Device Metadata
{
  status: 'active'
  enrolled_at: timestamp
  last_seen: timestamp
  trust_level: 'high'
  tailscale_device_id: string
  tailscale_hostname: string
  tailscale_ip: string
  tailscale_os: string
  tailscale_tags: string[]
  metadata: {
    tailscale_online: boolean
    tailscale_last_seen: string
  }
}

Device Events

Logged to device_events table:
  • tailscale_auth_key_generated - Auth key created
  • tailscale_enrollment_complete - Device enrolled successfully
  • tailscale_sync - Device status synchronized

Error Handling

error
string
Error message
Common errors:
  • Tailscale OAuth credentials not configured - Missing client ID/secret
  • Failed to obtain Tailscale access token - OAuth failure
  • Device not found in Tailscale network - Device hasn’t enrolled
  • Failed to generate Tailscale auth key - API key generation failed
  • Authorization required - Missing auth header
  • Invalid authentication - Invalid JWT

API Endpoints Used

The function interacts with these Tailscale API endpoints:
  • POST /api/v2/oauth/token - OAuth token acquisition
  • GET /api/v2/whoami - Get tailnet information
  • GET /api/v2/tailnet/{tailnet}/devices - List devices
  • GET /api/v2/device/{deviceId} - Get device details
  • POST /api/v2/tailnet/{tailnet}/keys - Generate auth keys
  • devices - Local device records
  • device_events - Device activity log
  • organization_tailscale_config - Per-org Tailscale configuration
  • audit_logs - API call audit trail

Build docs developers (and LLMs) love