Skip to main content

Authentication Methods

Midday supports three authentication methods:
  1. API Keys - For server-to-server integrations
  2. OAuth 2.0 - For third-party applications
  3. Supabase JWT - For authenticated user sessions
All authentication methods use the Authorization header with a Bearer token:
Authorization: Bearer <token>

API Keys

API keys are the recommended method for server-to-server integrations. They provide scoped access to your team’s data.

Creating an API Key

API keys can be created through the Midday dashboard or programmatically using the tRPC API:
1

Navigate to Settings

Go to your team settings in the Midday dashboard
2

Create API Key

Click “Create API Key” and provide a name and select scopes
3

Save Securely

Copy the API key immediately - it will only be shown once
API keys are sensitive credentials. Store them securely and never commit them to version control.

API Key Format

API keys follow this format:
mid_{64_character_hex_string}
Example: mid_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2

Using API Keys

curl https://api.midday.ai/transactions \
  -H "Authorization: Bearer mid_your_api_key_here"

API Key Scopes

API keys support granular permission scopes. You can grant access to specific resources:
apis.all
scope
Full access to all resources (read and write)
apis.read
scope
Read-only access to all resources

Resource-Specific Scopes

  • bank-accounts.read - Read bank account data
  • bank-accounts.write - Create and update bank accounts
  • transactions.read - Read transaction data
  • transactions.write - Create and update transactions
  • invoices.read - Read invoice data
  • invoices.write - Create, update, and delete invoices
  • customers.read - Read customer data
  • customers.write - Create and update customers
  • documents.read - Read and download documents
  • documents.write - Upload and delete documents
  • tracker-entries.read - Read time entries
  • tracker-entries.write - Create and update time entries
  • tracker-projects.read - Read projects
  • tracker-projects.write - Create and update projects
  • teams.read / teams.write - Team management
  • users.read / users.write - User management
  • inbox.read / inbox.write - Inbox management
  • insights.read - Financial insights
  • reports.read - Financial reports
  • tags.read / tags.write - Tag management
  • search.read - Search functionality
  • chat.read / chat.write - AI chat
  • notifications.read / notifications.write - Notifications

Managing API Keys

API keys can be managed through the tRPC API:
// List API keys for your team
const apiKeys = await client.apiKeys.get.query();

// Create a new API key
const { key, data } = await client.apiKeys.upsert.mutate({
  name: 'Production Server',
  scopes: ['apis.all'],
});

// Update an API key (name and scopes only)
await client.apiKeys.upsert.mutate({
  id: 'existing_key_id',
  name: 'Updated Name',
  scopes: ['apis.read'],
});

// Delete an API key
await client.apiKeys.delete.mutate({
  id: 'key_id_to_delete',
});
When you create an API key, you’ll receive a notification email with details about the key creation including IP address and timestamp.

OAuth 2.0

OAuth 2.0 is recommended for third-party applications that need to access user data on behalf of users.

OAuth Flow

Midday implements the OAuth 2.0 Authorization Code flow with PKCE support:
1

Register Your Application

Create an OAuth application in the Midday dashboard to obtain your client_id and client_secret
2

Authorization Request

Redirect users to the authorization endpoint
3

User Consent

User grants or denies permission to your application
4

Authorization Code

User is redirected back with an authorization code
5

Token Exchange

Exchange the authorization code for an access token
6

API Access

Use the access token to make API requests

Step 1: Authorization Request

Redirect users to the authorization endpoint:
GET https://api.midday.ai/oauth/authorize
client_id
string
required
Your application’s client ID
redirect_uri
string
required
URI to redirect to after authorization (must be registered)
scope
string
required
Space-separated list of scopes (e.g., invoices.read transactions.read)
state
string
required
Random string to prevent CSRF attacks
code_challenge
string
PKCE code challenge (required for public clients)
code_challenge_method
string
Must be S256 if using PKCE
Example:
https://api.midday.ai/oauth/authorize?
  client_id=your_client_id&
  redirect_uri=https://yourapp.com/callback&
  scope=invoices.read%20transactions.read&
  state=random_state_string&
  response_type=code

Step 2: Handle Authorization Response

After user consent, they’ll be redirected to your redirect_uri:
https://yourapp.com/callback?code=AUTH_CODE&state=random_state_string

Step 3: Exchange Code for Access Token

curl -X POST https://api.midday.ai/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "AUTH_CODE",
    "redirect_uri": "https://yourapp.com/callback",
    "client_id": "your_client_id",
    "client_secret": "your_client_secret",
    "code_verifier": "PKCE_CODE_VERIFIER"
  }'
Response:
{
  "access_token": "mid_access_token_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "mid_refresh_token_...",
  "scope": "invoices.read transactions.read"
}

OAuth Access Tokens

OAuth access tokens have the prefix mid_access_token_ and are valid for 1 hour.
curl https://api.midday.ai/transactions \
  -H "Authorization: Bearer mid_access_token_your_token_here"

Refreshing Access Tokens

When your access token expires, use the refresh token to obtain a new one:
curl -X POST https://api.midday.ai/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "mid_refresh_token_...",
    "client_id": "your_client_id",
    "client_secret": "your_client_secret"
  }'

Revoking Tokens

Revoke an access or refresh token when no longer needed:
curl -X POST https://api.midday.ai/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{
    "token": "mid_access_token_...",
    "client_id": "your_client_id",
    "client_secret": "your_client_secret"
  }'

PKCE for Public Clients

PKCE (Proof Key for Code Exchange) is required for public clients (mobile apps, SPAs) and recommended for all OAuth flows.
  1. Generate a code verifier (random string)
  2. Create a code challenge: BASE64URL(SHA256(code_verifier))
  3. Send code_challenge and code_challenge_method=S256 in authorization request
  4. Send code_verifier in token exchange request

Supabase JWT Tokens

If you’re building a custom frontend that uses Supabase authentication, you can use the Supabase JWT token directly:
const { data: { session } } = await supabase.auth.getSession();

const response = await fetch('https://api.midday.ai/transactions', {
  headers: {
    'Authorization': `Bearer ${session.access_token}`,
  },
});
Supabase JWT tokens automatically grant apis.all scope for authenticated users.

Authentication Errors

401 Unauthorized
error
Invalid or missing authentication credentials
{
  "error": "Unauthorized",
  "description": "Authorization header required"
}
403 Forbidden
error
Valid credentials but insufficient permissions
{
  "error": "Forbidden",
  "description": "Insufficient permissions. Required scopes: invoices.write. Your scopes: invoices.read"
}
Common authentication errors:
ErrorDescriptionSolution
Authorization header requiredNo Authorization header sentAdd Authorization: Bearer <token> header
Invalid authorization schemeWrong scheme usedUse Bearer scheme, not Basic or others
Token requiredEmpty tokenProvide a valid token after Bearer
Invalid token formatToken doesn’t match expected formatCheck token starts with mid_
Invalid API keyAPI key not found or revokedGenerate a new API key
User not foundUser associated with token doesn’t existContact support
Invalid or expired access tokenOAuth token expiredRefresh the access token

Security Best Practices

Store Securely

Store API keys in environment variables or secret managers, never in code

Rotate Regularly

Rotate API keys periodically and after any suspected compromise

Use Minimal Scopes

Grant only the minimum scopes needed for your use case

Monitor Usage

Monitor API key usage and check lastUsedAt timestamps
If an API key is compromised, delete it immediately from the dashboard or API. All requests using that key will be rejected immediately.

Build docs developers (and LLMs) love