Skip to content

CLO-121 -- A service declares how it authenticates in one door, Authentication - #987

Merged
czpython merged 1 commit into
mainfrom
paulo/clo-121-druks-one-credential-type-per-service-replaces-the
Oct 25, 2026
Merged

czpython merged 1 commit into
mainfrom
paulo/clo-121-druks-one-credential-type-per-service-replaces-the

Conversation

@czpython

@czpython czpython commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Closes CLO-121.

What changed

A service declares how it authenticates in one nested class, Authentication, found by name as Settings is. It names the service's ways as instances of the kinds in druks.services.auth, under fixed names, and carries what the provider does differently as classmethods.

  • api_key = auth.ApiKey(): a pasted key. Owns api_key. Linear, Jira, Twilio, WAHA, Voice, Speech to text.
  • jwt = auth.Jwt(): an app's private key. Owns private_key. GitHub.
  • oauth = auth.Oauth(...): the service's own OAuth app. Druks installs it and acts with the grant. Owns client_id and client_secret; takes the endpoints, the identity facts, and install_params. Slack, Linear.
  • sign_in = auth.SignIn(...): an OAuth client people only sign in through, with no install and no grant. Owns client_id and client_secret. GitHub.
class Linear(Service):
    class Settings(BaseModel):
        webhook_secret: SecretStr = Field(title="Webhook secret")

    class Authentication(auth.Authentication):
        api_key = auth.ApiKey()
        oauth = auth.Oauth(
            authorization_endpoint="https://linear.app/oauth/authorize",
            token_endpoint="https://api.linear.app/oauth/token",
            identity_key="subject",
            install_params={"actor": "app", "scope": "read,write"},
        )
  • A kind owns its credential; Settings holds the rest: Jira's email, Twilio's account_sid, GitHub's app_id, the webhook secrets. No Settings field has a blank default. The card shows Settings first, then the kinds in the order api_key, jwt, oauth, sign_in. One row stores them all.
  • api_key, jwt, and oauth are how Druks acts as the service, and a service holds one at a time: with two declared, each is pasted whole or left out; a pasted key ends the installed app's grant, and an install clears the key. sign_in stands apart. A service declares oauth or sign_in, not both. Another attribute holding a kind, or a kind under the wrong name, fails at import.
  • People sign in through the client, oauth or sign_in, when it names identity_key. GitHub's sign_in does; the reviewer inherits the same Authentication without it and writes nothing.
  • The provider's behavior lives on Authentication, with defaults on the base: get_authorization, get_identity, get_consent_query, read_grant, is_grant_revoked, get_install_endpoint, complete_install, and issue_token. GitHub mints its per-repo installation token there; Slack reads authed_user there.
  • An install stores the service's own grant: a vault row with no account, as the service's other rows are. A partial unique index keeps one live grant per service (migration b7d2e4a9c1f3). Service.get_grant() and get_access_token() read it. Slack's bot token lives there.
  • Every install goes through the sign-in door, GitHub included: the App manifest asks request_oauth_on_install, and the door starts at GitHub's installations page. GithubApp is the abstract GitHub App that Github and GithubReviewer extend.
  • The OAuth facts live only on the kind; nothing mirrors them. is_managed() stays at the manager seams: the OAuth client, the configuration sync, resources, and webhooks.
  • Gone: actor_token_name, get_install_params, Slack's pasted bot token and its verify, Linear's and Slack's install overrides.
  • The call pickup payload names the voice key api_key, and druks-calls reads it so.

@mintlify

mintlify Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
druks 🟢 Ready View Preview Oct 25, 2026, 4:45 PM

💡 Tip: Enable Automations to automatically generate PRs for you.

@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 6d601e9 to 8bfa5a6 Compare October 24, 2026 19:41
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 8bfa5a6 to 4530d77 Compare October 24, 2026 19:42
@czpython czpython changed the title CLO-121 -- One Credential type per service replaces the is_managed() branches CLO-121 -- A service's Integration declares its app, and an install stores its grant Oct 24, 2026
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 4530d77 to 7917676 Compare October 24, 2026 20:53
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 7917676 to aa3c5b6 Compare October 24, 2026 20:58
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from aa3c5b6 to 9151610 Compare October 24, 2026 20:59
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 9151610 to f7fff0b Compare October 24, 2026 21:06
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from f7fff0b to b527d5a Compare October 24, 2026 21:09
@czpython czpython changed the title CLO-121 -- A service's Integration declares its app, and an install stores its grant CLO-121 -- A service declares how it authenticates: ApiKey, Oauth, or Jwt Oct 25, 2026
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from b527d5a to 034ed72 Compare October 25, 2026 12:37
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 034ed72 to 89eee3f Compare October 25, 2026 15:47
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 89eee3f to 4f2ce30 Compare October 25, 2026 15:50
@czpython czpython changed the title CLO-121 -- A service declares how it authenticates: ApiKey, Oauth, or Jwt CLO-121 -- A service declares how it authenticates in one door, Authentication Oct 25, 2026
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from 4f2ce30 to aa1793c Compare October 25, 2026 16:22
@czpython
czpython force-pushed the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch from aa1793c to 4dec095 Compare October 25, 2026 16:45
@czpython
czpython merged commit af4021b into main Oct 25, 2026
7 checks passed
@czpython
czpython deleted the paulo/clo-121-druks-one-credential-type-per-service-replaces-the branch October 25, 2026 16:50

This branch was successfully deployed

1 active deployment
staging - docs — 4dec095a Deployed Oct 25, 2026 by mintlify[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant