Skip to content →
Sign upOpen app

OAuth 2.0 authentication

Linear supports OAuth2 authentication, which is recommended if you’re building applications to integrate with Linear.

It is highly recommended you create a workspace for the purpose of managing the OAuth2 Application, as each admin user will have access.

OAuth2 applications created from October 1, 2025 onwards will have refresh tokens enabled by default with no option to disable them.

Create an OAuth2 application

Create a new OAuth2 Application and configure the redirect callback URLs to your application.

Redirect user access requests to Linear

When authorizing a user to the Linear API, redirect to an authorization URL with correct parameters and scopes:

GET https://linear.app/oauth/authorize HTTP/1.1

Name

Description

client_id

(required) Client ID provided when you create the OAuth2 Application

redirect_uri

(required) Redirect URI

response_type=code

(required) Expected response type

scope

(required) Comma separated list of scopes:

  • read - (Default) Read access for the user's account. This scope will always be present.
  • write - Write access for the user's account. If your application only needs to create comments, use a more targeted scope
  • issues:create - Allows creating new issues and their attachments
  • comments:create - Allows creating new issue comments
  • timeSchedule:write - Allows creating and modifying time schedules
  • admin - Full access to admin level endpoints. You should never ask for this permission unless it's absolutely needed

state

(optional) Prevents CSRF attacks and should always be supplied. Read more about it here

prompt=consent

(optional) The consent screen is displayed every time, even if all scopes were previously granted. This can be useful if you want to give users the opportunity to connect multiple workspaces.

actor

Define how the OAuth application should create issues, comments and other changes:

  • user - (Default) Resources are created as the user who authorized the application. This option should be used if you want each user to do their own authentication
  • app - Resources are created as the application. This option should be used for agents and service accounts or agents.

Example

GET https://linear.app/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URL&state=SECURE_RANDOM&scope=read HTTP/1.1
 
GET https://linear.app/oauth/authorize?client_id=client1&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Foauth%2Fcallback&response_type=code&scope=read,write HTTP/1.1

Handle the redirect URLs you specified in the OAuth2 Application

Once the user approves your application they will be redirected back to your application, with the OAuth authorization code in the URL params.

Any state parameter you specified in step 2 will also be returned in the URL params and must match the value specified in step 2. If the values do not match, the request should not be trusted.

Example

GET https://example.com/oauth/callback?code=9a5190f637d8b1ad0ca92ab3ec4c0d033ad6c862&state=b1ad0ca92 HTTP/1.1

Exchange code for an access token

After receiving the code, you can exchange it for a Linear API access token:

POST https://api.linear.app/oauth/token HTTP/1.1

Pass parameters in body as URL-encoded form submission, where the Content-Type header must be application/x-www-form-urlencoded.

Parameter

Description

code

(required) Authorization code from the previous step

redirect_uri

(required) Same redirect URI which you used in the previous step

client_id

(required) Application's client ID

client_secret

(required) Application's client secret

grant_type=authorization_code

(required)

Response

After a successful request, a valid access token will be returned in the response.

If your application has refresh tokens enabled (default behavior for applications created from October 1, 2025 onwards), your response will contain a refresh token along with an access token. The access token is valid for 24 hours and will need to be refreshed when it expires. Example response:

{  
  "access_token": "00a21d8b0c4e2375114e49c067dfb81eb0d2076f48354714cd5df984d87b67cc",
  "token_type": "Bearer",  
  "expires_in": 86399,  
  "scope": "read write",
  "refresh_token": "sz0c8ffy95zj2ff6bh1hiausauw3dbfsu4gly1z4p49b5odqv8l7owunb654vg1f",
}

If your application does not have refresh tokens enabled, your response will contain an access token that is valid for 10 years. Example response:

{
  "access_token": "00a21d8b0c4e2375114e49c067dfb81eb0d2076f48354714cd5df984d87b67cc",
  "token_type": "Bearer",
  "expires_in": 315705599,
  "scope": "read write"
}

Note: OAuth apps created prior to Dec 1, 2023 will instead return scope as an array of strings in the token response.

Refresh an access token

If your application uses refresh tokens, you'll need to use the refresh token you receive alongside your access token to retrieve a new access token when the previous one expires.

For authorization, you have two options:

  1. Use HTTP basic authentication by passing a Base64-encoded client_id:client_secret string as an authorization header: Authorization: Basic <base64(client_id:client_secret)>
  2. Pass client_id and client_secret as parameters
POST https://api.linear.app/oauth/token HTTP/1.1

Pass parameters in body as URL-encoded form submission, where the Content-Type header must be application/x-www-form-urlencoded.

Parameter

Description

refresh_token

(required) Refresh token from the previous step

grant_type=refresh_token

(required)

client_id

(optional, based on authorization method) Application's client ID

client_secret

(optional, based on authorization method) Application's client secret

Response

After a successful request, a new valid access token and a new refresh token will be returned in the response:

{  
  "access_token": "fxra4u0msw3bagb9rdn2i641bs52m9zo8ksoxljouygcu31nh8s2jf8fygbepy16",
  "token_type": "Bearer",  
  "expires_in": 86399,  
  "scope": "read write",
  "refresh_token": "qjmj51q8f8fnwe188702jarfqxwhdy6r5ivqy4yjuhw2crubm5e7nyu84un3marx",
}

Make an API request

Once you have obtained a valid access token, you can make a request to Linear's GraphQL API. You can initialize the Linear Client with the access token:

const client = new LinearClient({ accessToken: response.access_token })
const me = await client.viewer

Or pass the token as an authorization header: Authorization: Bearer <ACCESS_TOKEN>

curl https://api.linear.app/graphql \
  -X POST \
  -H "Content-Type: application/json" \
  -H 'Authorization: Bearer <ACCESS_TOKEN>' \
  --data '{ "query": "{ viewer { id name } }" }' \

Revoke an access token

To revoke a user's access to your application pass the access token as Bearer token in the authorization header (Authorization: Bearer <ACCESS_TOKEN>) or as the access_token form field.

You can also revoke access using a refresh token by passing it as the refresh_token form field.

POST https://api.linear.app/oauth/revoke HTTP/1.1

Response

Expected HTTP status:

  • 200 - token was revoked
  • 400 - unable to revoke token (e.g. token was already revoked)
  • 401 - unable to authenticate with the token

Migrate to using refresh tokens

To ease the transition to refresh tokens for OAuth2 applications that aren't currently using them, we've added a temporary endpoint to migrate any old, long-lived access token to a new, short-lived access token with a refresh token.

POST https://api.linear.app/oauth/migrate_old_token HTTP/1.1

Pass parameters in body as URL-encoded form submission, where the Content-Type header must be application/x-www-form-urlencoded.

Parameter

Description

access_token

(required) Existing long-lived access token

client_id


(required) Application's client ID

client_secret


(required) Application's client secret