Back to docs
Backend API

Authentication & Authorization

Dagy supports multiple authentication methods and enforces role-based access control (RBAC) on all API endpoints.

Authentication Methods

1. Access Tokens (Default)

Access tokens are issued via POST /auth/login and stored with a configurable TTL.

Obtaining a token:

curl -X POST https://api.dagy.io/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "user@example.com"}'

Response:

{
  "access_token": "dagy_at_a1b2c3d4...",
  "token_type": "Bearer",
  "expires_at": 1738723200
}

Using the token:

curl https://api.dagy.io/flows \
  -H "Authorization: Bearer dagy_at_a1b2c3d4..."

Configuration:

Environment VariableDescriptionDefault
DAGY_USERSUsers table name-
DAGY_ACCESS_TOKENSAccess tokens table name-
DAGY_ACCESS_LOGSAccess logs table (optional audit)-
DAGY_ACCESS_TOKEN_TTL_SECONDSToken lifetime86400 (24h)

Tokens are stored locally by the CLI at ~/.dagy/credentials.

2. API Keys

API keys provide programmatic access with scoped permissions. They are created via POST /api-keys and identified by a dagy_ prefix.

Creating an API key:

curl -X POST https://api.dagy.io/api-keys \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"name": "CI Pipeline", "scopes": ["flows.read", "runs.trigger"]}'

The full API key is returned only once in the creation response. Store it securely.

Using an API key:

curl https://api.dagy.io/runs \
  -H "Authorization: Bearer dagy_sk_x1y2z3..."

Key features:

  • SHA-256 hashed at rest (only the key_prefix is stored for display)
  • Scoped permissions: keys with explicit scopes are restricted to those permissions
  • Keys with no scopes default to full owner access
  • Managed via POST /api-keys, GET /api-keys, DELETE /api-keys/{key_id}

3. JWT Authentication (Optional)

When enabled, the API validates JSON Web Tokens against a JWKS endpoint. This integrates with identity providers like Clerk, Auth0, or Okta.

Configuration:

Environment VariableDescription
DAGY_JWT_REQUIREDSet to true to require JWT auth
DAGY_JWT_ISSUERExpected iss claim value
DAGY_JWT_AUDIENCEExpected aud claim value
DAGY_JWKS_URLURL to the JWKS key set

Using JWT:

curl https://api.dagy.io/flows \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."

Fallback Behavior

If JWT is disabled and access-token tables are not configured, the API runs in development mode: all requests are accepted with a default identity (org_id: "default", role: "owner").

Role-Based Access Control (RBAC)

Every authenticated request resolves to an identity with an organization role. Dagy enforces a static permission matrix with 4 roles and 22 granular permissions.

Permission Matrix

PermissionOwnerAdminDeveloperViewer
flows.readYesYesYesYes
flows.writeYesYesYes-
flows.deleteYesYes--
runs.readYesYesYesYes
runs.triggerYesYesYes-
runs.cancelYesYesYes-
schedules.readYesYesYesYes
schedules.writeYesYesYes-
secrets.readYesYes--
secrets.writeYesYes--
admin.membersYesYes--
admin.orgYes---
admin.api_keysYesYes--
admin.auditYesYes--
billing.readYesYesYesYes
billing.writeYes---
environments.readYesYesYesYes
environments.writeYesYesYes-
notifications.readYesYesYesYes
notifications.writeYesYesYes-
sensors.readYesYesYesYes
sensors.writeYesYesYes-

How Permission Checks Work

Each endpoint calls require_permission(identity, "permission.name") before executing business logic. If the user's role lacks the required permission, the API returns:

HTTP 403 Forbidden
{
  "detail": "Permission denied: flows.write required"
}

Managing Roles

View the permission matrix:

curl https://api.dagy.io/orgs/{org_id}/roles \
  -H "Authorization: Bearer <token>"

Change a member's role:

curl -X PATCH https://api.dagy.io/orgs/{org_id}/members/user@example.com/role \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"role": "developer"}'

Role changes are audit-logged automatically.

Super Admin

In addition to org-scoped RBAC roles, Dagy has a super admin flag: a platform-level boolean on the user record that is separate from the 4 organization roles. Super admins can perform cross-org administrative operations that are not available to any org-scoped role.

How It Works

The super_admin field is a boolean stored on the user record. When a request hits a super-admin-gated endpoint, the API calls require_super_admin(identity), which checks identity["super_admin"]. If the flag is not true, the API returns:

HTTP 403 Forbidden
{
  "detail": "Super admin access required"
}

Super admin status is not granted through org membership or role assignment; it must be set directly on the user record in the database.

Capabilities

Super admins have access to 16 endpoints across three categories:

Customer Management (/admin/customers/*):

  • List, view, and update customer organizations
  • View customer members, usage, audit logs, and sessions
  • Suspend and reactivate organizations
  • Adjust credit balances
  • Revoke user sessions

Exception Trace Management (/admin/exceptions/*):

  • List and view exception traces across all organizations
  • Download trace files (requires s3:DeleteObject IAM permission for deletion)
  • Delete exception traces

Organization Impersonation (/admin/impersonate/{org_id}):

  • Impersonate any customer organization with owner-level access
  • Sets the X-Impersonate-Org header context for subsequent requests
  • All impersonation actions are audit-logged

See the Super Admin API Reference for full endpoint documentation.

Key Differences from RBAC Roles

AspectRBAC RolesSuper Admin
ScopePer-organizationPlatform-wide
AssignmentVia org membershipDirect user record flag
RolesOwner, Admin, Developer, ViewerBoolean (true/false)
EndpointsOrg-scoped resourcesCross-org admin operations

Audit Logging

All authentication and authorization events are tracked:

  • Access token creation and usage (via access logs)
  • API key creation and deletion
  • Role changes
  • Permission denial events
  • All mutation operations across all endpoints

Query the audit trail via GET /audit-logs (requires admin.audit permission).

Security Best Practices

  1. Rotate API keys regularly: Delete old keys and create new ones
  2. Use scoped API keys: Grant only the permissions each integration needs
  3. Enable JWT for production: Use a proper identity provider instead of access tokens
  4. Monitor audit logs: Review authentication events for anomalies
  5. Use HTTPS: All API communication should be encrypted in transit
  6. Store secrets securely: Use Dagy's built-in encrypted secret management instead of environment variables for sensitive configuration