Skip to content

Authentication

Manager supports multiple authentication methods for different use cases.

Authentication Methods

Personal Access Tokens (PAT)

For user-driven API access.

Use cases:

  • CLI tools
  • Scripts
  • Third-party integrations
  • Development/testing

Security: PBKDF2 with 600,000 iterations (OWASP 2023)

Machine Users

For service-to-service authentication.

Use cases:

  • Backend services
  • Automated workflows
  • Trigger execution
  • System integrations

Methods: Bearer token OR Basic auth

Personal Access Tokens

Creating a PAT

  1. Navigate to Personal Access Tokens in sidebar
  2. Click Create Token
  3. Enter Token Name (e.g., "CLI Access")
  4. Optional: Set Expiration Date
  5. Click Create
  6. Copy the token - shown only once!

Using a PAT

Include in HTTP headers:

bash
curl -H "Authorization: Bearer pfy_abc123..." \
  https://manager.example.com/graphql

With GraphQL client:

typescript
const client = createClient({
  url: "https://manager.example.com/graphql",
  fetchOptions: {
    headers: {
      authorization: `Bearer ${personalAccessToken}`,
    },
  },
});

Managing PATs

View Tokens:

  • List all your tokens
  • See last used time
  • Check expiration

Revoke Token:

  1. Find token in list
  2. Click Delete
  3. Confirm deletion
  4. Token is immediately invalidated

Best Practices:

  • Name tokens descriptively
  • Set expiration dates
  • Rotate tokens regularly
  • Revoke unused tokens
  • Never commit tokens to git

Machine Users

Creating a Machine User

  1. Navigate to Machine Users
  2. Click Create Machine User
  3. Enter Name
  4. Select Authentication Type:
    • Bearer Token - Token-based (recommended)
    • Basic Auth - Username/password
  5. Click Create
  6. Copy credentials - shown only once!

Bearer Token Authentication

Simpler and more secure:

bash
curl -H "Authorization: Bearer mu_xyz789..." \
  https://manager.example.com/api/machine/check
typescript
const response = await fetch("/api/machine/register-backend", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${machineUserToken}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    callback_url: "https://backend.example.com/triggers",
    application_id: "app-uuid",
  }),
});

Basic Authentication

Username and password:

bash
curl -u "username:password" \
  https://manager.example.com/api/machine/check
typescript
const credentials = btoa(`${username}:${password}`);
const response = await fetch("/api/machine/check", {
  headers: {
    Authorization: `Basic ${credentials}`,
  },
});

Machine User Permissions

Machine users are scoped to:

  • Single tenant - Cannot access other tenants
  • Assigned applications - Only apps they're registered for
  • Specific endpoints - Limited API surface

API Endpoints

Check Authentication (Machine User)

Verify machine user credentials:

http
GET /api/machine/check
Authorization: Bearer <token>

Response:

json
{
  "authenticated": true,
  "machine_user_id": "uuid",
  "tenant_id": "uuid",
  "message": "Authentication successful"
}

Register Backend

Register for trigger execution:

http
POST /api/machine/register-backend
Authorization: Bearer <token>
Content-Type: application/json

{
  "callback_url": "https://backend.example.com/triggers",
  "version": "1.0.0",
  "application_id": "uuid"
}

Response:

json
{
  "success": true,
  "backend_id": "uuid",
  "message": "Backend registered successfully"
}

Security Best Practices

Token Storage

Do:

  • Store in environment variables
  • Use secrets management (HashiCorp Vault, AWS Secrets Manager)
  • Encrypt at rest

Don't:

  • Commit to version control
  • Hardcode in source code
  • Share via unsecured channels

Token Rotation

  1. Create new token
  2. Update applications to use new token
  3. Verify new token works
  4. Revoke old token

Access Control

  • Use least privilege principle
  • Create separate tokens per service
  • Revoke tokens when no longer needed
  • Monitor token usage in audit logs

Network Security

  • Use HTTPS only
  • Restrict by IP if possible
  • Implement rate limiting
  • Monitor for unusual patterns

Troubleshooting

401 Unauthorized

Reasons:

  • Invalid token
  • Expired token
  • Token revoked
  • Wrong authentication header format

Fix:

  1. Verify token is correct
  2. Check token hasn't expired
  3. Ensure header format: Authorization: Bearer <token>
  4. Create new token if needed

403 Forbidden

Reasons:

  • Valid authentication but insufficient permissions
  • Accessing wrong tenant's resources
  • Machine user not assigned to application

Fix:

  1. Verify tenant/application access
  2. Check user permissions
  3. Ensure correct resource IDs

Token Not Working After Creation

Check:

  1. Did you copy the entire token?
  2. Are there extra spaces or newlines?
  3. Is the header formatted correctly?
  4. Try the /api/machine/check endpoint to test

Example: Backend Service Authentication

typescript
// backend-service.ts
import fetch from "node-fetch";

const MANAGER_URL = process.env.MANAGER_URL;
const MACHINE_TOKEN = process.env.MACHINE_USER_TOKEN;
const APP_ID = process.env.APPLICATION_ID;

// Register with Manager
async function registerBackend() {
  const response = await fetch(`${MANAGER_URL}/api/machine/register-backend`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${MACHINE_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      callback_url: "https://my-backend.com/triggers",
      version: "1.0.0",
      application_id: APP_ID,
    }),
  });

  if (!response.ok) {
    throw new Error(`Registration failed: ${response.statusText}`);
  }

  const data = await response.json();
  console.log("Backend registered:", data.backend_id);
}

// Verify authentication
async function checkAuth() {
  const response = await fetch(`${MANAGER_URL}/api/machine/check`, {
    headers: {
      Authorization: `Bearer ${MACHINE_TOKEN}`,
    },
  });

  const data = await response.json();
  console.log("Authenticated:", data.authenticated);
}

// Start service
async function start() {
  await checkAuth();
  await registerBackend();
  console.log("Service ready");
}

start();

See Also