No way to mint an access token for a bot account when OIDC delegated auth is enabled #2044
Labels
No labels
Abandoned
Blocked
Bug
Changelog
Added
Changelog
Missing
Changelog
None
Cherry-picking
Database
Dependencies
Dependencies/Renovate
Difficulty
Easy
Difficulty
Hard
Difficulty
Medium
Documentation
Enhancement
Good first issue
Help wanted
Inherited
Matrix/Administration
Matrix/Appservices
Matrix/Auth
Matrix/Client
Matrix/Core
Matrix/E2EE
Matrix/Federation
Matrix/Hydra
Matrix/MSC
Matrix/Media
Matrix/T&S
Merge
Merge/Manual
Merge/Squash
Meta
Meta/CI
Meta/Packaging
Priority
Blocking
Priority
High
Priority
Low
Security
Status
Confirmed
Status
Duplicate
Status
Invalid
Status
Needs Investigation
Support
bob the builder
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
continuwuation/continuwuity#2044
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
With delegated OIDC authentication configured (
[global.oauth.oidc]), Continuwuity behaves as ifcompatibility_mode = "exclusive", which is the documented and desired behaviour. What I couldn't find, though, is any remaining way to obtain a plain access token for a bot account, I may well have missed a supported path here, so please point me at it if one exists.Bots and scripts generally authenticate with a long-lived access token. Today, on an OIDC-only server, there is no supported way to create one. To be clear: this is only about minting a session. Presenting an existing token (
Authorization: Bearer …) still works fine, tokens issued before enabling OIDC keep working indefinitely.m.login.tokenis listed above because it is a login flow that also goes through/login, not because bearer auth is affected.What I verified (Continuwuity 26.6.2, OIDC delegated to Pocket ID)
GETandPOST /_matrix/client/v3/login→404 M_UNRECOGNIZED("User-interactive authentication is not available on this server"), for bothm.login.passwordandm.login.token.POST /_matrix/client/v1/login/get_tokenstill exists (401 without auth), but is unusable: the login token it mints can only be redeemed through/login, which is gone.!admin usersofferscreate-user,reset-password,enable-login,disable-login,deactivate, … but nothing that returns an access token.!admin query rawprovidesraw-get/raw-del/ iteration, but noraw-put, so a token row cannot be inserted manually either.!admin users enable-login <user>has no effect here:/loginis rejected at the route level, before any per-user flag is consulted.So
create-userhands you a password that cannot be used to log in.Workaround
Temporarily comment out the
[global.oauth.oidc]block, restart,POST /loginwith a chosendevice_id, then restore the config and restart again.Two useful observations from doing this:
expires_in_ms, norefresh_token, unlike an OAuth-issued one, which suits a long-running bot.It works, but it means briefly re-opening password login server-wide, which rather defeats the point of running OIDC-exclusive.
Why appservices don't cover this
Appservice registration does provide a static
as_token, but an appservice token has no device, which makes E2EE awkward for bots that behave as ordinary clients (e.g. anything built on mautrix in client mode, needing a stabledevice_idand its own crypto store).Proposal
An admin command that mints a token directly, never reopening legacy auth:
!admin users create-token <user_id> [--device-id <id>]…and/or a one-step convenience wrapper for the common case:!admin users create-bot <localpart>which creates the account and returns a ready-to-use access token. An alternative would be to make the existingenable-login/disable-loginflags meaningful under exclusive mode — i.e. allow legacy login only for accounts explicitly flagged, keeping the endpoint closed for everyone else. The primitive already exists, but it currently has no effect.If a new command is the way to go, I'd lean toward the admin one, since it never re-enables password authentication, but you know the codebase far better than I do.
Happy to help test whichever direction you prefer.
It's worth mentioning that bots are capable of using the OAuth device flow (which mautrix also supports - Gomuks is an example of a program using this) if they are unable to do standard authorization code flows for OAuth2. If a command is added to issue permanent tokens, it will be a workaround, and will not remain in the server forever. Codebases should be migrating to next-gen auth as soon as possible, because legacy auth is... legacy, and rapidly fading away.
For future reference, please write issues yourself. This could have been "I cannot find a way to issue a permanent access token for an account, please add a command for this", rather than a whole thesis.
Thanks, that's exactly the pointer I needed, and the architectural point is fair. I'd much rather do this properly than get a workaround that's on borrowed time.
One thing I can't reconcile, though: on 26.6.2 my
/_matrix/client/v1/auth_metadataadvertises onlywith no
device_authorization_endpoint. So a bot attempting the device flow has nothing to discover. Is it implemented but unadvertised, planned for a later or am I looking in the wrong place?For context on why people reach for static tokens today: the client side isn't quite there yet either. matrix-dart-sdk (FluffyChat, Commet) currently can't complete even the authorization-code flow against an OIDC-only server, its
checkHomeserver()aborts on the legacy/logincheck before OIDC discovery runs (fix open at famedly/matrix-dart-sdk#2412). That's not an argument against next-gen auth, just why the transition is bumpy right now.Two follow-up thoughts, if I may.
First, the device flow still authenticates a user, so getting a token for
@hermes-botmeans provisioning a separate identity in my IdP for every bot, each with its own credential, and approving in a private window so as not to authorise as myself. A device flow assumes a human who merely lacks a browser; a bot has no human at all.Second, on "a command issuing permanent tokens would be a workaround", I think that depends on what it issues. If an admin command minted a proper next-gen session (scoped, refreshable, revocable) rather than a permanent legacy token,
wouldn't that be next-gen auth, just with the grant initiated by server authority instead of user consent? The admin can already create and deactivate accounts; requiring an IdP round-trip to provision a bot on their own server seems like ceremony without added security.
Also worth noting:
create-useralready creates accounts with no IdP identity at all, but nothing can then authenticate as them.if i wanted to talk to an LLM agent id open chatgpt, please interface directly to describe the issue YOU are having
English is not my first language, so yes i have it reworked by ai. Not for me, but for the comfort of the people i'm talking to, especially on an issue where i try not to make you lose time. But the problem, the tests and the questions are mine, as far as i understand them. I'm using a bot, and i'm trying to make it connect seamlessly to matrix, and i don't think i'm alone on this, that's all.
Anyway, thanks a lot for your time and your response.
Br,