Problem
An application that runs when the user is not present — the Scheduler is the motivating case —
needs to call DIAL as that user, with that user's current permissions, days after the user set
the task up.
Today this is done with an OAuth external service: the user logs in at the identity provider and a
stored refresh token is redeemed before each run. It works, but the login is per application and
per service, so every application that wants offline behaviour drags the user through its own IdP
round-trip and keeps its own refresh token. Each one is a separate long-lived credential to store,
rotate and revoke.
Proposal
Move the round-trip rather than remove it: once per user, platform-wide, instead of once per
application.
Two decisions, made by two different people:
| Who |
Decides |
Recorded as |
| The user |
may DIAL act as me while I am away? |
offline credentials — one refresh token, platform-wide, never handed to an application |
| A DIAL admin |
may this application use that, for anyone? |
admin consent — one record per (application, service) |
Neither works alone: credentials with no consent reach no application, and consent with no
credentials has no identity to act with.
The user is not asked about individual applications. Their consent is to offline use of their own
identity; which applications may exercise it is an administrative decision. This is a real trade
and should be agreed deliberately — an admin's approval reaches every user who has enabled offline
credentials, not only users who opted into that application. It mirrors how enterprise IdPs handle
admin consent, and it is what keeps the feature deployable without prompting every user about every
app.
Scope — core
GET/POST /v1/user/offline-credentials, /signin, /signout — the user's own credentials.
Status doubles as "how to connect", so chat needs no per-provider configuration of its own.
- A per-provider offline OAuth client in the identity-provider settings, distinct from chat's
client. Its refresh token is what scheduled runs depend on.
POST/DELETE /v1/applications/{appId}/external-services/{id}/consent — admin only.
- A
DIAL_NATIVE authentication type, and a redemption branch on /obo-credentials that checks
consent, refreshes only when the stored token has expired, and returns the access token.
- Audit events naming the application and the owner — the only record tying an action to an app.
- A status contract that does not pretend a per-service login exists for this type.
🤖 Generated with Claude Code
Problem
An application that runs when the user is not present — the Scheduler is the motivating case —
needs to call DIAL as that user, with that user's current permissions, days after the user set
the task up.
Today this is done with an OAuth external service: the user logs in at the identity provider and a
stored refresh token is redeemed before each run. It works, but the login is per application and
per service, so every application that wants offline behaviour drags the user through its own IdP
round-trip and keeps its own refresh token. Each one is a separate long-lived credential to store,
rotate and revoke.
Proposal
Move the round-trip rather than remove it: once per user, platform-wide, instead of once per
application.
Two decisions, made by two different people:
Neither works alone: credentials with no consent reach no application, and consent with no
credentials has no identity to act with.
The user is not asked about individual applications. Their consent is to offline use of their own
identity; which applications may exercise it is an administrative decision. This is a real trade
and should be agreed deliberately — an admin's approval reaches every user who has enabled offline
credentials, not only users who opted into that application. It mirrors how enterprise IdPs handle
admin consent, and it is what keeps the feature deployable without prompting every user about every
app.
Scope — core
GET/POST /v1/user/offline-credentials,/signin,/signout— the user's own credentials.Status doubles as "how to connect", so chat needs no per-provider configuration of its own.
client. Its refresh token is what scheduled runs depend on.
POST/DELETE /v1/applications/{appId}/external-services/{id}/consent— admin only.DIAL_NATIVEauthentication type, and a redemption branch on/obo-credentialsthat checksconsent, refreshes only when the stored token has expired, and returns the access token.
🤖 Generated with Claude Code