The server
linear_server.py
scope_separator is the comma Linear documents. dead_grant_errors is how
Linear says a grant is gone: Refresh behaviour.
revocation is how a user is disconnected: Disconnecting.
Scopes
Each tool declares what an OAuth grant needs for it, from Linear’s list:read is on every grant (“this scope will always be present”), so an agent that
only files issues asks to change nothing else:
linear_scopes.py
admin, though creating and deleting one takes only
write; Linear’s own refusal says so, and
scripts/live_linear_scopes_check.py asks it for every tool. A personal API key
carries the account’s full access and takes no scopes.
A call the grant does not cover raises
InsufficientScope with the scope Linear
names, the narrowest the tool lists first: “Invalid scope: write or
comments:create required” gives needed == ['comments:create']. Linear sends
it with 400 to a mutation and 200 to a query.
Connecting a user
linear_users.py
Refresh behaviour
Linear refuses a refresh token that is spent, past its 30-minute grace, or unknown withinvalid_request (“Invalid refresh token”) in a 400, where RFC
6749 says invalid_grant. dead_grant_errors declares it, so a disconnected
user is asked about once a minute and the error’s reauthorize is true. Linear
uses the same code for a missing parameter, which a refresh from Charter never
has.
A pasted personal key
A user who pastes a personal API key instead gets aStaticTokenProvider(key)
from the same linear_for. Linear wants a personal key with no scheme and an
OAuth token as Bearer, and refuses each in the other’s shape. The pack tells
them apart by Linear’s lin_api_ prefix, so the two kinds of user can share
one configuration.
Disconnecting
TheSubjectProvider the pack is configured with builds the user’s client from
your store and revokes the grant, in one call:
linear_disconnect.py
oauth/revoke, with no client
credentials and with token_type_hint=refresh_token. Linear’s docs offer the
hint “to help the server identify the token”; measured live, it is needed:
without it, a live refresh token gets 401 Token not found and the grant
stays. With it, Linear answers 200 and the access token is refused at once.
A token already revoked gets 401 (“Token has already been revoked.”), where
Linear’s docs give “token was already revoked” as their example of a 400, so
both count as gone and revoke() returns False.
A pasted personal key was made by the user, and only they can delete it, in
Linear’s settings. Delete your row.
Where the rest is
- Register a Linear OAuth application — the screens, the redirect URL, the scopes
- Getting the grant — the route, the session,
state, PKCE - Connect your users’ accounts — every pack’s providers, side by side
- Packs — the Linear tools