Adding Linear provisions a resource (the upstream Linear API at https://api.linear.app, with default scopes pre-set) and a provider for Linear’s OAuth issuer - auto-provisioned on first install, or reused if you already connected another Linear resource.
Your application calls Keycard’s token-exchange endpoint with the user’s identity, gets back a token scoped to this resource, and uses it to call Linear directly. Identity, policy, and audit log apply to every exchange - the OAuth client secret stays inside Keycard. Each exchange is recorded in the audit log with the user identity, the resource accessed, and the policy decision.
Scopes
Section titled “Scopes”OAuth permissions Keycard requests on install. Override or add scopes in Console.
- read
- default
- write
- default
- issues:create
- comments:create
- timeSchedule:write
- admin
- app:assignable
- app:mentionable
- customer:read
- customer:write
- initiative:read
- initiative:write
Use Linear from your code
Section titled “Use Linear from your code”Call Linear from your application with a Keycard-issued token scoped to this resource.
After installing Linear, your application exchanges a Keycard-issued access token for a token scoped to this resource. Pass the user’s access token as the subject_token.
from keycardai.oauth import Client, BasicAuth, TokenTypeimport requests
# Exchange the user's Keycard token for a Linear token.with Client( "https://<zone-id>.keycard.cloud", auth=BasicAuth("<your-client-id>", "<your-client-secret>"),) as client: response = client.exchange_token( subject_token=user_access_token, subject_token_type=TokenType.ACCESS_TOKEN, resource="https://api.linear.app", )
# Call Linear directly with the exchanged token.r = requests.get( "https://api.linear.app/<endpoint>", headers={"Authorization": f"Bearer {response.access_token}"},)import { TokenExchangeClient } from "@keycardai/oauth/tokenExchange";
const client = new TokenExchangeClient("https://<zone-id>.keycard.cloud", { clientId: "<your-client-id>", clientSecret: "<your-client-secret>",});
const response = await client.exchangeToken({ subjectToken: userAccessToken, resource: "https://api.linear.app",});
// Call Linear directly with the exchanged token.const res = await fetch("https://api.linear.app/<endpoint>", { headers: { Authorization: `Bearer ${response.accessToken}` },});See the OAuth SDK → Token Exchange reference for the full client API.
Register your OAuth credentials with Keycard so the resource can issue tokens.
Create a Linear OAuth application
Section titled “Create a Linear OAuth application”- Go to Linear Settings → API → Applications
- Fill in:
- Application name: A descriptive name
- Redirect callback URLs: The redirect URI provided by Keycard
- Description: Optional description of your integration
- Click Create
Get credentials
Section titled “Get credentials”- After creating the application, note the Client ID and Client Secret
Register in Keycard
Section titled “Register in Keycard”- Open Keycard Console → your zone → Resources
- Click Explore Resources
- Find and click Linear in the catalog
- In the configuration dialog:
- Enter the Client ID and Client Secret from your Linear OAuth application
- Review the User scopes - the defaults (
read,write) are pre-populated
- Click Add Linear API
Troubleshooting
Section titled “Troubleshooting”Common errors when wiring Linear into your zone.
Error: Authentication required
The access token is invalid or expired. Reconnect the provider in Keycard Console. Linear tokens have a fixed expiry - Keycard handles refresh automatically if the provider issued a refresh token.
GraphQL errors in response
If the test returns a 200 status but the response contains GraphQL errors, check:
- The granted scopes include
read(required for theviewerquery) - The user has an active Linear account
Related
Section titled “Related”- Catalog overview - browse other API and MCP servers
- Access policies - control who can use Linear
- Identity providers - control who can sign in