Flow Logo

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

  1. Minimize token lifespan - Use short-lived access tokens
  2. Rotate regularly - Don't reuse tokens indefinitely
  3. Revoke on logout - Always call logout when ending sessions
  4. 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 or given_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

  1. Create a dedicated user account via admin panel
  2. Set can_run_pipelines permission if needed
  3. 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

Previous
API Overview