OAuth & Service Canvas
Queria integrates with authenticated external APIs through Service Canvas -- special DSL canvases with purpose = SERVICE that describe how to authorize an OAuth2 provider and which operations they expose. User credentials are stored encrypted in a vault and referenced by consumer canvases (CHAT, INGESTION, WIDGET) through the connection_ref type.
BYO (Bring Your Own)
V1/V2 only support the BYO approach: the tenant brings their own OAuth client_id and client_secret registered at the provider. Queria does not provide or certify proprietary OAuth apps toward third-party providers.
When you need it
| Use case | Example |
|---|---|
| Chat that sends messages to a channel | Slack, Microsoft Teams |
| Pipeline that creates calendar events | Google Calendar, Microsoft 365 |
| Automatic ingestion from SaaS | Notion, Confluence, GitHub Issues |
| Constructor calling paid APIs | Stripe, Salesforce, HubSpot |
| Advanced cloud storage | Google Drive with delegated permissions, OneDrive |
For basic cloud storage with personal user login, standard connectors are already documented in Settings > Cloud Storage.
Architecture
+----------------------------------------+
| Service Canvas "Slack OAuth" |
| purpose = SERVICE |
| +--------------+ +------------------+|
| | oauth2_config| | operation_def[] ||
| | client_id | | post_message ||
| | client_secret| | list_channels ||
| | auth_url | | get_user_email ||
| | token_url | +------------------+|
| | scopes[] | |
| +--------------+ |
+----------------------------------------+
^ referenced by
|
+-----------------------------+
| CHAT consumer canvas |
| ... -> external_tool( |
| serviceCanvasId='slack', |
| operationId='post_msg') |
+-----------------------------+
| runtime
v
+------------------------------------+
| ExternalServiceConnection (DB) |
| per (serviceCanvasId, |
| companyId, userId) |
| -> accessToken (AES-256 encrypted)|
| -> refreshToken (encrypted) |
| -> scopes, expiresAt |
+------------------------------------+Three key concepts:
- Service canvas -- provider definition (who it is, how to authorize, which endpoints it exposes).
- External_tool node -- used in CHAT/INGESTION canvases to call an operation on the service canvas.
- Connection -- DB row with encrypted tokens for the pair (user, service).
Creating a service canvas
The admin follows these steps:
1. Register the OAuth app at the provider
Example Slack:
- Go to
https://api.slack.com/appsand create a new app. - Configure Redirect URL =
https://admin.queria.pro/api/oauth/callback/slack(replace with your tenant Queria domain). - Set the required scopes (e.g.
chat:write,channels:read). - Copy
client_idandclient_secret.
2. Create the service canvas
- Admin panel > DSL & Pipelines > OAuth & Service Canvas > New.
- Choose a provider template (Slack, Google Workspace, Microsoft 365, GitHub, Notion, Custom).
- Paste
client_idandclient_secretin theoauth2_confignode fields. Theclient_secretis server-side encrypted (AES-256-GCM). - Verify
auth_url,token_url,scopes(pre-filled by template, editable). - Add
operation_defnodes with HTTP method, path, input/output parameters. You can import them from OpenAPI 3.x (for providers that expose it). - Save. The canvas is validated and marked
ACTIVE.
3. Users authorize
On the service canvas a Connect button appears. When a user clicks it:
- Redirect to the provider for authorization (user consent, scopes).
- Provider redirects back with a
code. - Backend exchanges
codeforaccess_token+refresh_token. - Tokens are encrypted and stored in
ExternalServiceConnectionfor(serviceCanvasId, companyId, userId). - The user sees the connection as Connected and can revoke it at any time.
Using the connection in a canvas
In the CHAT/INGESTION canvas add an external_tool node:
{
"type": "external_tool",
"params": {
"serviceCanvasId": "slack-oauth-canvas-id",
"operationId": "post_message",
"inputs": {
"channel": "{{sys.target_channel}}",
"text": "{{llm_writer_1.output}}"
},
"outputName": "slack_response"
}
}At runtime:
- The engine loads the service canvas.
- Finds the
post_messageoperation. - Resolves the connection for
(serviceCanvasId, companyId, ctx.userId). - If the token has expired, refreshes it automatically.
- Executes the HTTP call with
Authorization: Bearer <access_token>. - Writes the response to
sys.slack_response.
Connection management
Admin panel > OAuth & Service Canvas > [service] > Connections:
- Table of all connections for that service canvas (users, scopes, status, last use).
- Possible states:
ACTIVE,EXPIRED(refresh failed),REVOKED,ERROR. - Revoke on the Queria side (removes encrypted tokens) and -- if the provider supports it -- calls the remote revoke endpoint.
- Audit log: who authorized, when, with which scopes, which canvas consumed the connection.
Security
- Tokens at rest: encrypted with AES-256-GCM. The master key
LLM_VAULT_KEKis derived fromJWT_SECRET(in production make sure it's not the defaultdev-secret-change-me). - Tokens in transit: HTTPS only to the provider; internal calls go through the isolated Docker network.
- Minimum scopes: the template suggests minimum scopes per operation. Don't request
admin:*if not needed. - Per-user: every connection belongs to a single user. When a canvas runs, it uses the token of the user who triggered the execution (
ctx.userId). - Audit: every OAuth
external_toolcall logs(userId, serviceCanvasId, operationId, statusCode, latencyMs)toIntegrationCallLog.
Limits and roadmap
Current V1/V2:
- Only
authorization_codeflow. - BYO client only (no Queria-owned verified apps).
- No
client_credentials(M2M) -- on V3 roadmap. - No
device_codeflow. - No Google Workspace domain-wide delegation.
- No inbound webhooks from provider (separate roadmap).
- OpenAPI 3.x operation import in V1.2.
Best practices
- One service canvas per provider, even if you use multiple operations: simplifies token management.
- Document the scopes in the canvas name or description: "Slack (chat:write only)" beats "Slack OAuth".
- Limit active operation_def: add only the operations actually used.
- Test on pilot tenant: before enabling for everyone, try on an internal company.
- Watch EXPIRED: a drop in successful refreshes often signals the provider revoked the app or changed policies.
Queria v3.5.0 -- External Tools OAuth V2 + Service Canvas