Authentication and permissions
Authenticate requests with Authorization: Bearer YOUR_TOKEN. Use a browser or CLI session for interactive development and an explicitly scoped API key for application or CI access. Connect to your workspace walks through both credential paths.
On this page
Credential typesVerify the current identityCreate, inspect, and revoke API keysAPI key scope compatibilityWorkspace rolesAccess-token exchangeDevice authorization for CLI integrationsCredential types
| Credential | Obtain it | Behavior |
|---|---|---|
| Dagy access token | Complete dagy login, or exchange an authenticated sign-in token through /auth/login | Represents a user. Workspace membership determines access. Use returned expires_at; the default lifetime is 24 hours. |
| API key | An owner/admin creates it through /api-keys; Settings also creates default read-only keys | Starts with dagy_, belongs to one workspace, and uses explicit scopes. Optional expiry is set at creation. |
| Configured sign-in token | The workspace's sign-in flow | Accepted when its issuer and signature match the configured identity provider. Arbitrary third-party JWTs are not accepted. |
Never put credentials in URLs or source control. Keep application keys on a trusted server or in CI secrets, not in browser JavaScript. The full API key appears only in its creation response.
Verify the current identity
curl --fail-with-body "$DAGY_API_URL/me" \
-H "Authorization: Bearer $DAGY_TOKEN"For a session, the response contains user_email, org_id, and role. An API key's role can be empty because permissions come from scopes. GET /users/me adds org_name and account metadata.
A session can select a workspace using X-Org-Id. Obtain IDs from GET /orgs. The workspace must be one of the user's memberships. If selection cannot be resolved, the API can fall back to another membership; verify /me with the same header before writes. An API key always uses its creation workspace.
Create, inspect, and revoke API keys
Creating or deleting a key requires admin.api_keys, held by owners and admins. For a service that deploys flows and runs them:
curl --fail-with-body -X POST "$DAGY_API_URL/api-keys" \
-H "Authorization: Bearer $DAGY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "release-worker",
"scopes": ["flows.read", "flows.write", "runs.read", "runs.trigger"],
"expires_in_days": 30
}'Here DAGY_TOKEN must already contain a credential allowed to manage keys. For a working bootstrap from dagy login, use Create an application key.
The response includes key_id, key, key_prefix, name, scopes, created_at, and expires_at. Store key immediately in your secret manager. expires_at is Unix seconds; no expiry is null. Omitting scopes defaults to flows.read and runs.read. An empty scopes list grants full owner-equivalent access. Supply an explicit nonempty list for application keys.
| Operation | Result |
|---|---|
GET /api-keys | Metadata, scopes, expiry, creator, and last_used_at; never the full key. |
DELETE /api-keys/{key_id} | Revokes the key and returns {"status":"deleted"}. Missing/inaccessible keys return 404. |
Rotate by creating a replacement, updating the application, verifying it works, and deleting the old key. There is no in-place rotation or scope update endpoint. A user's logout does not revoke their API keys.
API key scope compatibility
Some endpoint families require an additional API key scope before the granular feature permission. Include both when designing a key:
| API key operation | Required scope combination |
|---|---|
| List schedules | runs.read and schedules.read |
Create/update through POST /schedules | runs.trigger and schedules.write |
Trigger with POST /schedules/{id}/trigger | runs.trigger |
| Patch a schedule | schedules.write |
Preview/create a backfill with POST /flows/{name}/backfill | runs.trigger and flows.write (or the additional admin scope in place of flows.write) |
| List/create workspaces or read their member/role routes | Additional admin scope; mutations can require granular permission too. |
| Add a member | admin and admin.members |
| List API keys | admin |
| Create/delete API keys | admin and admin.api_keys |
The literal admin key scope satisfies these compatibility checks; it is not a wildcard and does not replace granular permissions. A key with only admin cannot create a key. An owner/admin session does not need these API-key-specific scopes.
A run submission and monitoring key usually needs only runs.trigger and runs.read. A release key also needs flows.read and flows.write. Add scheduling or environment permissions only when the service manages those resources.
Workspace roles
There are four workspace roles and 35 granular permissions. Role permissions apply where the operation requires them; identity and several convenience/account reads require authentication without an additional granular permission. Consult the endpoint index.
| Permission | Owner | Admin | Developer | Viewer |
|---|---|---|---|---|
flows.read | Yes | Yes | Yes | Yes |
flows.write | Yes | Yes | Yes | No |
flows.delete | Yes | Yes | No | No |
runs.read | Yes | Yes | Yes | Yes |
runs.trigger | Yes | Yes | Yes | No |
runs.cancel | Yes | Yes | No | No |
schedules.read | Yes | Yes | Yes | Yes |
schedules.write | Yes | Yes | Yes | No |
secrets.read | Yes | Yes | Yes | No |
secrets.write | Yes | Yes | No | No |
nodes.read | Yes | Yes | Yes | Yes |
nodes.write | Yes | Yes | Yes | No |
nodes.delete | Yes | Yes | No | No |
admin.members | Yes | Yes | No | No |
admin.org | Yes | No | No | No |
admin.api_keys | Yes | Yes | No | No |
admin.audit | Yes | Yes | No | No |
billing.read | Yes | No | No | No |
billing.write | Yes | No | No | No |
environments.read | Yes | Yes | Yes | Yes |
environments.write | Yes | Yes | No | No |
notifications.read | Yes | Yes | Yes | No |
notifications.write | Yes | Yes | No | No |
sensors.read | Yes | Yes | Yes | No |
sensors.write | Yes | Yes | No | No |
dep_packages.read | Yes | Yes | Yes | Yes |
dep_packages.write | Yes | Yes | Yes | No |
connectors.read | Yes | Yes | Yes | Yes |
connectors.write | Yes | Yes | Yes | No |
connectors.delete | Yes | Yes | No | No |
connections.read | Yes | Yes | Yes | Yes |
connections.write | Yes | Yes | Yes | No |
connections.verify | Yes | Yes | Yes | No |
connections.use | Yes | Yes | Yes | No |
connections.delete | Yes | Yes | No | No |
secrets.read includes decrypted values. Do not give the developer role to someone who should only see secret names. The current flow-delete operation requires flows.write; the separate flows.delete permission does not restrict it to owners/admins. Workspace administration is distinct from reserved platform administration; organization ownership does not grant cross-workspace access.
Read the role matrix with GET /orgs/{org_id}/roles. Manage membership using Workspace administration.
Access-token exchange
POST /auth/login is an authenticated exchange, not sign-in from an email address alone. Supply a valid bearer credential that proves the same email:
curl --fail-with-body -X POST "$DAGY_API_URL/auth/login" \
-H "Authorization: Bearer $SIGN_IN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email":"developer@example.com"}'The response contains access_token, token_type: "Bearer", and expires_at. An existing unexpired access token may be returned again. A missing email claim, explicitly unverified email, or email mismatch returns 403. There is no general refresh-token endpoint; repeat authenticated sign-in when needed.
POST /auth/logout with a valid session requests revocation of the user's active Dagy access sessions. dagy logout also removes the local credential file. It does not terminate an identity-provider session or revoke keys.
Device authorization for CLI integrations
Most users should run dagy login. To implement a device client:
POST /auth/device/startwith{}. Keepdevice_codeprivate. Show the eight-digituser_codeand direct the user to the web application's/cli-callbackpage.- The signed-in browser sends
POST /auth/device/approvewith{"user_code":"12345678"}and its valid bearer token. Approval binds to that user and workspace. - The device polls
POST /auth/device/tokenwith{"device_code":"THE_RETURNED_DEVICE_CODE"}at the returned interval. - On success, save
access_token,expires_at,user_email, andorg_idsecurely.
The grant expires after five minutes and can be consumed once. Pending responses use HTTP 202 with status: "authorization_pending" and interval: 2. Concurrent redemption can return status: "slow_down" and interval: 3. Honor these intervals. HTTP 410 means start a new grant. Final 200 includes workspace_name; approval does not deliver the token to the browser.
Keep the device code and token out of URLs, telemetry, and logs. Complete models are in the OpenAPI reference.