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
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"
}'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();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:
{
"user": {
"id": "usr_abc123",
"email": "[email protected]",
"displayName": "John Doe",
"emailVerified": false
},
"token": "eyJhbGciOiJIUzI1NiIs...",
"message": "Verification email sent"
}Email Verification
# 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"}'// 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();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()# Resend verification email
curl -X POST https://api.hookbase.app/api/auth/resend-verification \
-H "Authorization: Bearer YOUR_JWT_TOKEN"// 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();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
curl -X POST https://api.hookbase.app/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-password"
}'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();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:
{
"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:
{
"requiresTwoFactor": true,
"challengeToken": "2fa-challenge-token"
}Complete the login with the TOTP code:
curl -X POST https://api.hookbase.app/api/auth/login/2fa \
-H "Content-Type: application/json" \
-d '{
"challengeToken": "2fa-challenge-token",
"code": "123456"
}'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();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
# Request password reset
curl -X POST https://api.hookbase.app/api/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'// 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();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()# 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"
}'// 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();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
# Redirect user to OAuth provider
# GitHub
GET https://api.hookbase.app/api/auth/oauth/github
# Google
GET https://api.hookbase.app/api/auth/oauth/googleThe 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:
# 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"}'// 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();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:
curl https://api.hookbase.app/api/organizations \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."const response = await fetch('https://api.hookbase.app/api/organizations', {
headers: {
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'
}
});
const data = await response.json();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:
curl -X POST https://api.hookbase.app/api/auth/refresh \
-H "Authorization: Bearer YOUR_JWT_TOKEN"const response = await fetch('https://api.hookbase.app/api/auth/refresh', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
});
const data = await response.json();import requests
response = requests.post(
'https://api.hookbase.app/api/auth/refresh',
headers={'Authorization': 'Bearer YOUR_JWT_TOKEN'}
)
data = response.json()Logout
curl -X POST https://api.hookbase.app/api/auth/logout \
-H "Authorization: Bearer YOUR_JWT_TOKEN"const response = await fetch('https://api.hookbase.app/api/auth/logout', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
});
const data = await response.json();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
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"]
}'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();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:
{
"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:
curl https://api.hookbase.app/api/sources \
-H "Authorization: Bearer whr_your_api_key"const response = await fetch('https://api.hookbase.app/api/sources', {
headers: {
'Authorization': 'Bearer whr_your_api_key'
}
});
const data = await response.json();import requests
response = requests.get(
'https://api.hookbase.app/api/sources',
headers={'Authorization': 'Bearer whr_your_api_key'}
)
data = response.json()API Key Prefixes
| Prefix | Environment |
|---|---|
whr_live_ | Production |
whr_test_ | Test/sandbox |
Available Scopes
| Scope | Description |
|---|---|
sources:read | Read sources |
sources:write | Create/update/delete sources |
destinations:read | Read destinations |
destinations:write | Create/update/delete destinations |
routes:read | Read routes |
routes:write | Create/update/delete routes |
events:read | Read events |
events:write | Replay events |
deliveries:read | Read deliveries |
analytics:read | Read analytics data |
admin | Full access |
Managing API Keys
List API Keys
curl https://api.hookbase.app/api/api-keys \
-H "Authorization: Bearer whr_your_api_key"const response = await fetch('https://api.hookbase.app/api/api-keys', {
headers: {
'Authorization': 'Bearer whr_your_api_key'
}
});
const data = await response.json();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
curl -X DELETE https://api.hookbase.app/api/api-keys/{keyId} \
-H "Authorization: Bearer whr_your_api_key"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();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
- Store securely: Use secure, HTTP-only cookies in browsers
- Short expiration: Tokens expire after 7 days
- Refresh proactively: Refresh tokens before they expire
- Logout on security events: Logout after password changes
For API Keys
- Use scoped keys: Only grant necessary permissions
- Rotate regularly: Rotate keys periodically
- Use environment variables: Never commit keys to code
- Monitor usage: Review API key activity in the dashboard
- Revoke unused keys: Delete keys that are no longer needed
Environment-Specific Keys
Create separate API keys for each environment:
# 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:
{
"error": "Unauthorized",
"message": "Invalid or expired token"
}403 Forbidden
Valid authentication but insufficient permissions:
{
"error": "Forbidden",
"message": "API key does not have required scope: sources:write"
}Example: Complete Auth Flow
// 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}` }
});