Skip to content

Authentication

Hookbase supports two authentication methods: JWT tokens and API keys.

JWT Tokens

JWT tokens are obtained by logging in and are used for browser-based access. Access tokens expire after 15 minutes; refresh tokens last 7 days.

Register

bash
curl -X POST https://api.hookbase.app/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "your-password",
    "displayName": "John Doe"
  }'
javascript
const response = await fetch('https://api.hookbase.app/api/auth/register', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: '[email protected]',
    password: 'your-password',
    displayName: 'John Doe'
  })
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/auth/register',
    headers={'Content-Type': 'application/json'},
    json={
        'email': '[email protected]',
        'password': 'your-password',
        'displayName': 'John Doe'
    }
)
data = response.json()

Response:

json
{
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "displayName": "John Doe",
    "emailVerified": false
  },
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "message": "Verification email sent"
}

Email Verification

bash
# Verify email with token from email link
curl -X POST https://api.hookbase.app/api/auth/verify-email \
  -H "Content-Type: application/json" \
  -d '{"token": "verification-token-from-email"}'
javascript
// Verify email with token from email link
const response = await fetch('https://api.hookbase.app/api/auth/verify-email', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    token: 'verification-token-from-email'
  })
});
const data = await response.json();
python
import requests

# Verify email with token from email link
response = requests.post(
    'https://api.hookbase.app/api/auth/verify-email',
    headers={'Content-Type': 'application/json'},
    json={'token': 'verification-token-from-email'}
)
data = response.json()
bash
# Resend verification email
curl -X POST https://api.hookbase.app/api/auth/resend-verification \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
javascript
// Resend verification email
const response = await fetch('https://api.hookbase.app/api/auth/resend-verification', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  }
});
const data = await response.json();
python
import requests

# Resend verification email
response = requests.post(
    'https://api.hookbase.app/api/auth/resend-verification',
    headers={'Authorization': 'Bearer YOUR_JWT_TOKEN'}
)
data = response.json()

Login

bash
curl -X POST https://api.hookbase.app/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "your-password"
  }'
javascript
const response = await fetch('https://api.hookbase.app/api/auth/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: '[email protected]',
    password: 'your-password'
  })
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/auth/login',
    headers={'Content-Type': 'application/json'},
    json={
        'email': '[email protected]',
        'password': 'your-password'
    }
)
data = response.json()

Response:

json
{
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "displayName": "John Doe"
  },
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expiresAt": "2024-01-22T10:30:00Z"
}

Login with 2FA

If the user has two-factor authentication enabled, the initial login returns a challenge:

json
{
  "requiresTwoFactor": true,
  "challengeToken": "2fa-challenge-token"
}

Complete the login with the TOTP code:

bash
curl -X POST https://api.hookbase.app/api/auth/login/2fa \
  -H "Content-Type: application/json" \
  -d '{
    "challengeToken": "2fa-challenge-token",
    "code": "123456"
  }'
javascript
const response = await fetch('https://api.hookbase.app/api/auth/login/2fa', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    challengeToken: '2fa-challenge-token',
    code: '123456'
  })
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/auth/login/2fa',
    headers={'Content-Type': 'application/json'},
    json={
        'challengeToken': '2fa-challenge-token',
        'code': '123456'
    }
)
data = response.json()

Forgot Password

bash
# Request password reset
curl -X POST https://api.hookbase.app/api/auth/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'
javascript
// Request password reset
const response = await fetch('https://api.hookbase.app/api/auth/forgot-password', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    email: '[email protected]'
  })
});
const data = await response.json();
python
import requests

# Request password reset
response = requests.post(
    'https://api.hookbase.app/api/auth/forgot-password',
    headers={'Content-Type': 'application/json'},
    json={'email': '[email protected]'}
)
data = response.json()
bash
# Reset password with token from email
curl -X POST https://api.hookbase.app/api/auth/reset-password \
  -H "Content-Type: application/json" \
  -d '{
    "token": "reset-token-from-email",
    "password": "new-secure-password"
  }'
javascript
// Reset password with token from email
const response = await fetch('https://api.hookbase.app/api/auth/reset-password', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    token: 'reset-token-from-email',
    password: 'new-secure-password'
  })
});
const data = await response.json();
python
import requests

# Reset password with token from email
response = requests.post(
    'https://api.hookbase.app/api/auth/reset-password',
    headers={'Content-Type': 'application/json'},
    json={
        'token': 'reset-token-from-email',
        'password': 'new-secure-password'
    }
)
data = response.json()

OAuth Login

bash
# Redirect user to OAuth provider
# GitHub
GET https://api.hookbase.app/api/auth/oauth/github

# Google
GET https://api.hookbase.app/api/auth/oauth/google

The OAuth flow redirects the user to the provider, then back to Hookbase with an auth token.

Device Flow (CLI)

The CLI uses the device authorization flow:

bash
# 1. Request device code
curl -X POST https://api.hookbase.app/api/auth/device \
  -H "Content-Type: application/json" \
  -d '{"clientId": "hookbase-cli"}'

# Response:
# {
#   "deviceCode": "abc123",
#   "userCode": "ABCD-1234",
#   "verificationUrl": "https://www.hookbase.app/auth/device",
#   "expiresIn": 900,
#   "interval": 5
# }

# 2. User visits verificationUrl and enters userCode
# 3. CLI polls for token
curl -X POST https://api.hookbase.app/api/auth/device/token \
  -H "Content-Type: application/json" \
  -d '{"deviceCode": "abc123", "clientId": "hookbase-cli"}'
javascript
// 1. Request device code
const deviceResponse = await fetch('https://api.hookbase.app/api/auth/device', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    clientId: 'hookbase-cli'
  })
});
const deviceData = await deviceResponse.json();

// Response:
// {
//   "deviceCode": "abc123",
//   "userCode": "ABCD-1234",
//   "verificationUrl": "https://www.hookbase.app/auth/device",
//   "expiresIn": 900,
//   "interval": 5
// }

// 2. User visits verificationUrl and enters userCode
// 3. CLI polls for token
const tokenResponse = await fetch('https://api.hookbase.app/api/auth/device/token', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    deviceCode: 'abc123',
    clientId: 'hookbase-cli'
  })
});
const tokenData = await tokenResponse.json();
python
import requests

# 1. Request device code
device_response = requests.post(
    'https://api.hookbase.app/api/auth/device',
    headers={'Content-Type': 'application/json'},
    json={'clientId': 'hookbase-cli'}
)
device_data = device_response.json()

# Response:
# {
#   "deviceCode": "abc123",
#   "userCode": "ABCD-1234",
#   "verificationUrl": "https://www.hookbase.app/auth/device",
#   "expiresIn": 900,
#   "interval": 5
# }

# 2. User visits verificationUrl and enters userCode
# 3. CLI polls for token
token_response = requests.post(
    'https://api.hookbase.app/api/auth/device/token',
    headers={'Content-Type': 'application/json'},
    json={'deviceCode': 'abc123', 'clientId': 'hookbase-cli'}
)
token_data = token_response.json()

Using JWT Tokens

Include the token in the Authorization header:

bash
curl https://api.hookbase.app/api/organizations \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
javascript
const response = await fetch('https://api.hookbase.app/api/organizations', {
  headers: {
    'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'
  }
});
const data = await response.json();
python
import requests

response = requests.get(
    'https://api.hookbase.app/api/organizations',
    headers={'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'}
)
data = response.json()

Token Refresh

Tokens expire after 7 days. Refresh before expiration:

bash
curl -X POST https://api.hookbase.app/api/auth/refresh \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
javascript
const response = await fetch('https://api.hookbase.app/api/auth/refresh', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  }
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/auth/refresh',
    headers={'Authorization': 'Bearer YOUR_JWT_TOKEN'}
)
data = response.json()

Logout

bash
curl -X POST https://api.hookbase.app/api/auth/logout \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
javascript
const response = await fetch('https://api.hookbase.app/api/auth/logout', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_JWT_TOKEN'
  }
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/auth/logout',
    headers={'Authorization': 'Bearer YOUR_JWT_TOKEN'}
)
data = response.json()

API Keys

API keys are recommended for programmatic access. They don't expire and can be scoped to specific permissions.

Creating an API Key

bash
curl -X POST https://api.hookbase.app/api/api-keys \
  -H "Authorization: Bearer whr_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI/CD Pipeline",
    "scopes": ["sources:read", "events:write"]
  }'
javascript
const response = await fetch('https://api.hookbase.app/api/api-keys', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer whr_your_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'CI/CD Pipeline',
    scopes: ['sources:read', 'events:write']
  })
});
const data = await response.json();
python
import requests

response = requests.post(
    'https://api.hookbase.app/api/api-keys',
    headers={
        'Authorization': 'Bearer whr_your_api_key',
        'Content-Type': 'application/json'
    },
    json={
        'name': 'CI/CD Pipeline',
        'scopes': ['sources:read', 'events:write']
    }
)
data = response.json()

Response:

json
{
  "id": "key_abc123",
  "name": "CI/CD Pipeline",
  "key": "whr_live_abc123xyz...",
  "scopes": ["sources:read", "events:write"],
  "createdAt": "2024-01-15T10:30:00Z"
}

WARNING

The full API key is only shown once. Store it securely!

Using API Keys

Include the API key in the Authorization header:

bash
curl https://api.hookbase.app/api/sources \
  -H "Authorization: Bearer whr_your_api_key"
javascript
const response = await fetch('https://api.hookbase.app/api/sources', {
  headers: {
    'Authorization': 'Bearer whr_your_api_key'
  }
});
const data = await response.json();
python
import requests

response = requests.get(
    'https://api.hookbase.app/api/sources',
    headers={'Authorization': 'Bearer whr_your_api_key'}
)
data = response.json()

API Key Prefixes

PrefixEnvironment
whr_live_Production
whr_test_Test/sandbox

Available Scopes

ScopeDescription
sources:readRead sources
sources:writeCreate/update/delete sources
destinations:readRead destinations
destinations:writeCreate/update/delete destinations
routes:readRead routes
routes:writeCreate/update/delete routes
events:readRead events
events:writeReplay events
deliveries:readRead deliveries
analytics:readRead analytics data
adminFull access

Managing API Keys

List API Keys

bash
curl https://api.hookbase.app/api/api-keys \
  -H "Authorization: Bearer whr_your_api_key"
javascript
const response = await fetch('https://api.hookbase.app/api/api-keys', {
  headers: {
    'Authorization': 'Bearer whr_your_api_key'
  }
});
const data = await response.json();
python
import requests

response = requests.get(
    'https://api.hookbase.app/api/api-keys',
    headers={'Authorization': 'Bearer whr_your_api_key'}
)
data = response.json()

Revoke API Key

bash
curl -X DELETE https://api.hookbase.app/api/api-keys/{keyId} \
  -H "Authorization: Bearer whr_your_api_key"
javascript
const response = await fetch('https://api.hookbase.app/api/api-keys/{keyId}', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer whr_your_api_key'
  }
});
const data = await response.json();
python
import requests

response = requests.delete(
    'https://api.hookbase.app/api/api-keys/{keyId}',
    headers={'Authorization': 'Bearer whr_your_api_key'}
)
data = response.json()

Security Best Practices

For JWT Tokens

  1. Store securely: Use secure, HTTP-only cookies in browsers
  2. Short expiration: Tokens expire after 7 days
  3. Refresh proactively: Refresh tokens before they expire
  4. Logout on security events: Logout after password changes

For API Keys

  1. Use scoped keys: Only grant necessary permissions
  2. Rotate regularly: Rotate keys periodically
  3. Use environment variables: Never commit keys to code
  4. Monitor usage: Review API key activity in the dashboard
  5. Revoke unused keys: Delete keys that are no longer needed

Environment-Specific Keys

Create separate API keys for each environment:

bash
# Production key
curl -X POST .../api-keys \
  -d '{"name": "Production API", "scopes": ["admin"]}'

# Staging key (read-only)
curl -X POST .../api-keys \
  -d '{"name": "Staging API", "scopes": ["sources:read", "events:read"]}'

Error Responses

401 Unauthorized

Missing or invalid authentication:

json
{
  "error": "Unauthorized",
  "message": "Invalid or expired token"
}

403 Forbidden

Valid authentication but insufficient permissions:

json
{
  "error": "Forbidden",
  "message": "API key does not have required scope: sources:write"
}

Example: Complete Auth Flow

javascript
// 1. Login to get JWT
const loginResponse = await fetch('https://api.hookbase.app/api/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: '[email protected]',
    password: 'password'
  })
});
const { token, user } = await loginResponse.json();

// 2. Get organizations
const orgsResponse = await fetch('https://api.hookbase.app/api/organizations', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const { data: orgs } = await orgsResponse.json();
const orgId = orgs[0].id;

// 3. Create an API key for programmatic use
const keyResponse = await fetch(`https://api.hookbase.app/api/organizations/${orgId}/api-keys`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'My App',
    scopes: ['sources:read', 'events:read']
  })
});
const { key } = await keyResponse.json();

// 4. Use API key for subsequent requests
const sourcesResponse = await fetch('https://api.hookbase.app/api/sources', {
  headers: { 'Authorization': `Bearer ${key}` }
});

Released under the MIT License.