API Documentation
API Authentication
Flow uses JWT (JSON Web Tokens) for API authentication. This guide explains how to obtain, use, and refresh authentication tokens.
Authentication Flow
┌─────────┐ ┌─────────┐
│ Client │ │ API │
└────┬────┘ └────┬────┘
│ │
│ 1. Login with credentials │
├───────────────────────────────────────►│
│ │
│ 2. Access token + Refresh token │
│◄───────────────────────────────────────┤
│ │
│ 3. API request with access token │
├───────────────────────────────────────►│
│ │
│ 4. Response │
│◄───────────────────────────────────────┤
│ │
│ ┌─────────────────────────────┐ │
│ │ Access token expires (5 min) │ │
│ └─────────────────────────────┘ │
│ │
│ 5. Refresh with refresh token │
├───────────────────────────────────────►│
│ │
│ 6. New access token │
│◄───────────────────────────────────────┤
│ │
Obtaining Tokens
Login Endpoint
Use the login endpoint to obtain initial tokens:
Endpoint: POST /login
Request:
curl -X POST https://api.flow.bio/login \
-H "Content-Type: application/json" \
-d '{
"username": "your-username",
"password": "your-password"
}'
Response:
{
"user": {
"id": 123456,
"username": "your-username",
"email": "user@example.com",
"first_name": "Your",
"last_name": "Name",
"is_admin": false,
"can_run_pipelines": true,
"groups": ["research-lab", "bioinformatics"]
},
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
Using the Python Client
import flowbio
client = flowbio.Client()
client.login("your-username", "your-password")
# Tokens are stored in the client
print(f"Logged in as: {client.user.username}")
Token Lifespan
- Access Token: 5 minutes
- Refresh Token: 7 days
Store the refresh token securely as it can be used to obtain new access tokens without re-authentication.
Using Tokens
Authorization Header
Include the access token in the Authorization header for all authenticated requests:
Authorization: Bearer <access_token>
JavaScript Example
const response = await fetch('https://api.flow.bio/me', {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const userData = await response.json();
console.log(userData);
Python Example
import requests
headers = {
'Authorization': f'Bearer {access_token}'
}
response = requests.get(
'https://api.flow.bio/samples/owned',
headers=headers
)
samples = response.json()
print(f"Found {samples['count']} samples")
Refreshing Tokens
When an access token expires, use the refresh token to obtain a new one without re-authenticating.
Refresh Endpoint
Endpoint: GET /token
# Get new access token using current token
curl -X GET https://api.flow.bio/token \
-H "Authorization: Bearer <current_access_token>"
Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
Automatic Token Refresh
Implement automatic token refresh in your client:
class FlowAPIClient {
constructor() {
this.accessToken = null;
this.refreshToken = null;
this.baseUrl = 'https://api.flow.bio/api';
}
async makeRequest(endpoint, options = {}) {
try {
return await this._request(endpoint, options);
} catch (error) {
if (error.status === 401 && this.refreshToken) {
// Token expired, refresh it
await this.refreshAccessToken();
return await this._request(endpoint, options);
}
throw error;
}
}
async refreshAccessToken() {
const response = await fetch(`${this.baseUrl}/token`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${this.accessToken}`
}
});
if (response.ok) {
const data = await response.json();
this.accessToken = data.access_token;
} else {
// Token expired, need to re-login
throw new Error('Token refresh failed - please login again');
}
}
async _request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}${endpoint}`, {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${this.accessToken}`
}
});
if (!response.ok) {
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
error.status = response.status;
throw error;
}
return response.json();
}
}
Python Client Authentication
The flowbio Python client handles authentication automatically:
import flowbio
# Initialize client
client = flowbio.Client()
# Login
client.login("username", "password")
# The client automatically handles token refresh
samples = client.get_samples()
Persistent Sessions
Save tokens to avoid re-authentication:
import json
import flowbio
# Save tokens
client = flowbio.Client()
client.login("username", "password")
with open('.flow_tokens.json', 'w') as f:
json.dump({
'access_token': client.access_token,
'refresh_token': client.refresh_token
}, f)
# Load tokens
with open('.flow_tokens.json', 'r') as f:
tokens = json.load(f)
client = flowbio.Client()
client.access_token = tokens['access_token']
client.refresh_token = tokens['refresh_token']
Logout
To invalidate tokens and end a session:
Endpoint: POST /logout
curl -X POST https://api.flow.bio/logout \
-H "Authorization: Bearer <access_token>"
This will:
- Invalidate the current access token
- Invalidate the refresh token
- End the user session
Security Best Practices
Token Storage
DO:
- Store tokens in secure, encrypted storage
- Use environment variables for server applications
- Implement proper token rotation
DON'T:
- Store tokens in plain text files
- Include tokens in version control
- Share tokens between users
- Log tokens
Token Transmission
DO:
- Always use HTTPS
- Include tokens only in headers
- Validate SSL certificates
DON'T:
- Send tokens in URL parameters
- Send tokens in request bodies (except for login)
- Use tokens over unencrypted connections
Token Lifecycle
- Minimize token lifespan - Use short-lived access tokens
- Rotate regularly - Don't reuse tokens indefinitely
- Revoke on logout - Always call logout when ending sessions
- Monitor usage - Track API calls for unusual patterns
Error Handling
Common Authentication Errors
Invalid Credentials:
{
"errors": [{
"message": "Invalid username or password",
"extensions": {
"code": "INVALID_CREDENTIALS"
}
}]
}
Expired Token:
{
"errors": [{
"message": "Token has expired",
"extensions": {
"code": "UNAUTHENTICATED"
}
}]
}
Invalid Token:
{
"errors": [{
"message": "Invalid authentication token",
"extensions": {
"code": "UNAUTHENTICATED"
}
}]
}
Handling Authentication Errors
import time
from functools import wraps
def with_auth_retry(max_retries=1):
def decorator(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
for attempt in range(max_retries + 1):
try:
return func(self, *args, **kwargs)
except AuthenticationError as e:
if attempt < max_retries and self.refresh_token:
self.refresh_access_token()
else:
raise
except RateLimitError as e:
if attempt < max_retries:
time.sleep(e.retry_after)
else:
raise
return wrapper
return decorator
class FlowClient:
@with_auth_retry(max_retries=2)
def get_samples(self):
# API call implementation
pass
Single Sign-On (SSO)
Flow supports OpenID Connect (OIDC) for enterprise SSO integration.
OIDC Login
Endpoint: POST /oidc-login
curl -X POST https://api.flow.bio/oidc-login \
-H "Content-Type: application/json" \
-d '{
"id_token": "<oidc_id_token_from_provider>"
}'
Response:
{
"user": {
"id": 123456,
"username": "user@company.com",
"email": "user@company.com",
"oidc_issuer": "https://sso.company.com",
"oidc_subject": "auth0|123456789"
},
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}
OIDC Configuration
Flow automatically creates or updates user accounts based on OIDC claims:
- Email: Used as username and email
- Name: Parsed from
name
orgiven_name
/family_name
claims - Groups: Mapped from
groups
claim if configured
Supported OIDC Providers
- Auth0
- Okta
- Azure AD
- Google Workspace
- Any OIDC-compliant provider
Python Client OIDC
import flowbio
client = flowbio.Client()
# Login with OIDC token
client.oidc_login(id_token)
# Or configure for automatic OIDC flow
client = flowbio.Client(
oidc_provider="https://sso.company.com",
oidc_client_id="flow-api-client"
)
Service Accounts
For automated systems and CI/CD pipelines, use service accounts with long-lived tokens.
Creating Service Accounts
- Create a dedicated user account via admin panel
- Set
can_run_pipelines
permission if needed - Generate long-lived refresh token:
import flowbio
# Admin creates service account
client = flowbio.Client()
client.login("admin", "password")
service_user = client.create_user(
username="pipeline-bot",
email="bot@company.com",
is_service_account=True
)
# Generate long-lived token
token = client.generate_service_token(
user_id=service_user.id,
expires_in_days=365
)
print(f"Service token: {token}")
Using Service Accounts
# Set as environment variable
export FLOW_SERVICE_TOKEN="<service_token>"
# Use in automation
curl -H "Authorization: Bearer $FLOW_SERVICE_TOKEN" \
https://api.flow.bio/pipelines
Service Account Benefits
- Long-lived tokens: Configurable expiration (up to 1 year)
- Audit trail: All actions tagged with service account
- Limited permissions: Only granted necessary access
- Separate rate limits: Higher limits for automation
- Revocable: Disable account to revoke all access
Next Steps
- REST API Reference - Complete endpoint documentation
- Python Client Guide - Using the flowbio library
- Permissions Guide - Understanding access control
- Error Handling - Handling API errors gracefully