Skip to main content

Authentication

Toggly supports multiple authentication methods for accessing the API, including OAuth 2.0, and JWT Bearer tokens.

Authentication Methods​

For machine-to-machine (M2M) API access, Toggly uses OAuth 2.0 Client Credentials flow. This is ideal for server-side applications, scripts, or automated processes.

Configuration​

  • Token Endpoint: https://auth.toggly.io/connect/token
  • Grant Type: client_credentials
  • Token Type: JWT Bearer
  • Required Scopes: openid, toggly

Obtaining Client Credentials​

  1. Log in to your Toggly account at https://app.toggly.io
  2. Navigate to Team Settings → API Keys
  3. Click Create API Key
  4. Copy your Client ID and Client Secret (store securely - the secret is only shown once)

Getting an Access Token​

Send a POST request to the token endpoint:

curl -X POST https://auth.toggly.io/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=openid toggly"

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "openid toggly"
}

Using the Access Token​

Include the access token in the Authorization header for all API requests:

curl -X GET https://app.toggly.io/api/v2/applications \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjE..."

Token Expiration​

  • Access tokens are valid for 1 hour (3600 seconds)
  • When a token expires, request a new one using the same client credentials
  • No refresh token is issued for client credentials flow

Best Practices​

  • Secure Storage: Never commit client secrets to source control. Use environment variables or secret management systems.
  • Token Caching: Cache access tokens and reuse them until they expire to minimize token requests.
  • Error Handling: Implement automatic token refresh when receiving 401 Unauthorized responses.
  • Scope Restrictions: Only request the scopes your application needs.

Example: Token Refresh Logic​

let cachedToken = null;
let tokenExpiry = null;

async function getAccessToken() {
// Return cached token if still valid
if (cachedToken && tokenExpiry && Date.now() < tokenExpiry) {
return cachedToken;
}

// Request new token
const response = await fetch('https://auth.toggly.io/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: process.env.TOGGLY_CLIENT_ID,
client_secret: process.env.TOGGLY_CLIENT_SECRET,
scope: 'openid toggly'
})
});

const data = await response.json();
cachedToken = data.access_token;
tokenExpiry = Date.now() + (data.expires_in * 1000) - 60000; // Refresh 1 min early

return cachedToken;
}

OAuth 2.0 / JWT Bearer (Interactive Login)​

The Toggly web application and Chrome Extension use OAuth 2.0 with JWT Bearer tokens for interactive user authentication:

  • Authorization Endpoint: https://auth.toggly.io/connect/authorize
  • Token Endpoint: https://auth.toggly.io/connect/token
  • Token Type: JWT Bearer
  • Scopes: openid, email, toggly

Token Lifecycle​

Token Issuance​

When you sign in to Toggly:

  1. You authenticate via OAuth 2.0 (with PKCE for the Chrome Extension)
  2. An access token and refresh token are issued
  3. The access token is valid for a limited time (typically 1 hour)
  4. The refresh token can be used to obtain new access tokens

Token Refresh​

Before an access token expires:

  1. The client sends the refresh token to the token endpoint
  2. A new access token is issued
  3. The new token replaces the old one
  4. The old token is no longer valid

Token Invalidation​

When you sign out, tokens are immediately invalidated server-side to prevent unauthorized access.

Token Invalidation API​

Endpoint​

POST /api/account/invalidate-token

Description​

Invalidates the current JWT access token by adding it to a server-side blacklist. This ensures the token cannot be used after logout, even if it hasn't expired yet.

Authentication​

Requires a valid JWT Bearer token in the Authorization header.

Request​

curl -X POST https://app.toggly.io/api/account/invalidate-token \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response​

Success (200 OK):

{
"message": "Token invalidated successfully"
}

Unauthorized (401):

{
"error": "invalid_token",
"error_description": "No bearer token provided"
}

Bad Request (400):

{
"error": "invalid_token",
"error_description": "Invalid JWT token format"
}

How It Works​

  1. Client Calls Endpoint: When signing out, the client sends a POST request with the access token
  2. Token Hashing: The server computes a SHA256 hash of the token (for security)
  3. Blacklist Storage: The token hash is stored in Redis with a TTL matching the token's expiration
  4. Validation Check: All subsequent API requests check if the token is blacklisted
  5. Automatic Cleanup: Blacklisted tokens are automatically removed when they expire

Security Features​

  • Immediate Revocation: Tokens are invalidated instantly, not after expiration
  • Hash Storage: Only a hash of the token is stored, never the full token
  • Automatic Expiry: Blacklist entries are automatically cleaned up
  • High Performance: Redis-based blacklist provides sub-millisecond lookup times
  • Privacy Preserving: No sensitive token data is persisted

Token Validation​

When you make an API request with a JWT Bearer token:

  1. Signature Verification: The token signature is verified using the public key
  2. Expiration Check: The token expiration time is checked
  3. Blacklist Check: The token is checked against the invalidation blacklist
  4. Claims Extraction: User claims (sub, role, teams) are extracted from the token

If any check fails, the request is rejected with 401 Unauthorized.

Best Practices​

1. Always Sign Out​

When you're done working, always sign out properly. This ensures your tokens are invalidated server-side:

// Chrome Extension automatically calls the invalidation endpoint
await authService.signOut();

2. Handle 401 Responses​

If you receive a 401 Unauthorized response, your token may have been invalidated or expired:

// Automatically refresh token or redirect to login
if (response.status === 401) {
await refreshToken();
// or
redirectToLogin();
}

3. Secure Token Storage​

Store tokens securely:

  • Browser: Use secure, HttpOnly cookies or browser storage APIs
  • Chrome Extension: Use chrome.storage.local (never localStorage)
  • Mobile Apps: Use secure storage (Keychain, Keystore)
  • Never: Store tokens in code, logs, or version control

4. Token Rotation​

For long-running applications, implement automatic token refresh:

// Refresh tokens before they expire
setInterval(async () => {
if (tokenExpiresInLessThan(5, 'minutes')) {
await refreshToken();
}
}, 5 * 60 * 1000); // Check every 5 minutes

5. Use HTTPS Only​

Always use HTTPS when sending tokens:

  • Never send tokens over HTTP
  • Verify SSL certificates
  • Use certificate pinning for mobile apps (optional)

Error Codes​

CodeDescriptionAction
401Unauthorized - invalid or expired tokenRefresh token or re-authenticate
403Forbidden - insufficient permissionsCheck user permissions
429Too many requests - rate limit exceededImplement exponential backoff

Token Claims​

JWT tokens issued by Toggly include these claims:

  • sub: User ID (e.g., ApplicationUsers/1-A)
  • email: User email address
  • name: User full name
  • role: User role (e.g., User, Admin)
  • team: Team IDs the user belongs to
  • primaryTeam: User's primary team ID
  • iat: Issued at timestamp
  • exp: Expiration timestamp
  • aud: Audience (optional)
  • iss: Issuer (https://auth.toggly.io)

Support​

For authentication issues: