Why Use This
This skill provides specialized capabilities for jeremylongshore's codebase.
Use Cases
- Developing new features in the jeremylongshore repository
- Refactoring existing code to follow jeremylongshore standards
- Understanding and working with jeremylongshore's codebase structure
Install Guide
2 steps - 1
- 2
Install inside Ananke
Click Install Skill, paste the link below, then press Install.
https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/main/plugins/saas-packs/linear-pack/skills/linear-install-auth
Skill Snapshot
Auto scan of skill assets. Informational only.
Valid SKILL.md
Checks against SKILL.md specification
Source & Community
Updated At May 23, 2026, 05:41 AM
Skill Stats
SKILL.md 218 Lines
Total Files 1
Total Size 7.1 KB
License MIT
---
name: linear-install-auth
description: 'Install and configure Linear SDK/CLI authentication.
Use when setting up a new Linear integration, configuring API keys,
OAuth2 flows, or initializing LinearClient in your project.
Trigger: "install linear", "setup linear", "linear auth",
"configure linear API key", "linear SDK setup", "linear OAuth".
'
allowed-tools: Read, Write, Edit, Bash(npm:*), Bash(pnpm:*), Bash(yarn:*), Grep
version: 1.0.0
license: MIT
author: Jeremy Longshore <[email protected]>
tags:
- saas
- linear
- api
- authentication
compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
---
# Linear Install & Auth
## Overview
Install the `@linear/sdk` TypeScript SDK and configure authentication for the Linear GraphQL API at `https://api.linear.app/graphql`. Supports personal API keys for scripts and OAuth 2.0 (with PKCE) for user-facing apps.
## Prerequisites
- Node.js 18+ (SDK is TypeScript-first, works in any JS environment)
- Package manager (npm, pnpm, or yarn)
- Linear account with workspace access
- For API key: Settings > Account > API > Personal API keys
- For OAuth: Create app at Settings > Account > API > OAuth applications
## Instructions
### Step 1: Install the SDK
```bash
set -euo pipefail
npm install @linear/sdk
# or: pnpm add @linear/sdk
# or: yarn add @linear/sdk
```
The SDK exposes `LinearClient`, typed models for every entity (Issue, Project, Cycle, Team), and error classes (`LinearError`, `InvalidInputLinearError`).
### Step 2: API Key Authentication (Scripts & Server-Side)
Generate a Personal API key at Linear Settings > Account > API > Personal API keys. Keys start with `lin_api_` and are shown only once.
```typescript
import { LinearClient } from "@linear/sdk";
// Environment variable (recommended)
const client = new LinearClient({
apiKey: process.env.LINEAR_API_KEY,
});
// Verify connection
const me = await client.viewer;
console.log(`Authenticated as: ${me.name} (${me.email})`);
```
**Environment setup:**
```bash
# .env (never commit)
LINEAR_API_KEY=lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# .gitignore
echo '.env' >> .gitignore
```
### Step 3: OAuth 2.0 Authentication (User-Facing Apps)
Linear supports the standard Authorization Code flow with optional PKCE. As of October 2025, newly created OAuth apps issue refresh tokens by default.
```typescript
import crypto from "crypto";
// 1. Build authorization URL
const SCOPES = ["read", "write", "issues:create"];
const state = crypto.randomBytes(16).toString("hex");
const authUrl = new URL("https://linear.app/oauth/authorize");
authUrl.searchParams.set("client_id", process.env.LINEAR_CLIENT_ID!);
authUrl.searchParams.set("redirect_uri", process.env.LINEAR_REDIRECT_URI!);
authUrl.searchParams.set("response_type", "code");
authUrl.searchParams.set("scope", SCOPES.join(","));
authUrl.searchParams.set("state", state);
// Optional PKCE:
// authUrl.searchParams.set("code_challenge", challenge);
// authUrl.searchParams.set("code_challenge_method", "S256");
// 2. Exchange authorization code for tokens
const tokenResponse = await fetch("https://api.linear.app/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: authorizationCode,
client_id: process.env.LINEAR_CLIENT_ID!,
client_secret: process.env.LINEAR_CLIENT_SECRET!,
redirect_uri: process.env.LINEAR_REDIRECT_URI!,
}),
});
const { access_token, refresh_token, expires_in } = await tokenResponse.json();
// 3. Create client with OAuth token
const client = new LinearClient({ accessToken: access_token });
```
**Available OAuth scopes:** `read`, `write`, `issues:create`, `admin`, `initiative:read`, `initiative:write`, `customer:read`, `customer:write`.
### Step 4: Token Refresh (OAuth)
```typescript
async function refreshAccessToken(refreshToken: string): Promise<string> {
const response = await fetch("https://api.linear.app/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: process.env.LINEAR_CLIENT_ID!,
client_secret: process.env.LINEAR_CLIENT_SECRET!,
}),
});
if (!response.ok) {
throw new Error(`Token refresh failed: ${response.status}`);
}
const tokens = await response.json();
// Store new refresh_token — Linear rotates it on each refresh
await saveTokens(tokens.access_token, tokens.refresh_token);
return tokens.access_token;
}
```
### Step 5: Validate Configuration on Startup
```typescript
function validateLinearConfig(): void {
const key = process.env.LINEAR_API_KEY;
if (!key) throw new Error("LINEAR_API_KEY environment variable is required");
if (!key.startsWith("lin_api_")) throw new Error("LINEAR_API_KEY must start with lin_api_");
if (key.length < 30) throw new Error("LINEAR_API_KEY appears truncated");
}
// Call before creating client
validateLinearConfig();
```
## Error Handling
| Error | Cause | Solution |
|-------|-------|----------|
| `Authentication required` | Invalid, expired, or missing API key | Regenerate at Settings > Account > API |
| `Invalid API key format` | Key doesn't start with `lin_api_` | Copy full key from Linear (shown once) |
| `Forbidden` | Token lacks required OAuth scope | Re-authorize with correct scopes |
| `invalid_grant` on token exchange | Code expired or PKCE verifier mismatch | Restart OAuth flow; codes expire quickly |
| `Module not found: @linear/sdk` | SDK not installed | Run `npm install @linear/sdk` |
| `ENOTFOUND api.linear.app` | DNS/firewall issue | Ensure outbound HTTPS to `api.linear.app` |
## Examples
### Raw GraphQL Without SDK
```typescript
const response = await fetch("https://api.linear.app/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": process.env.LINEAR_API_KEY!,
},
body: JSON.stringify({
query: `{ viewer { id name email } }`,
}),
});
const { data, errors } = await response.json();
if (errors) console.error("GraphQL errors:", errors);
else console.log("Viewer:", data.viewer);
```
### Server-to-Server (Client Credentials)
```typescript
// For apps without user interaction — uses client_credentials grant
const response = await fetch("https://api.linear.app/oauth/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.LINEAR_CLIENT_ID!,
client_secret: process.env.LINEAR_CLIENT_SECRET!,
scope: "read,write",
}),
});
const { access_token } = await response.json();
const client = new LinearClient({ accessToken: access_token });
```
## Resources
- [Linear SDK Getting Started](https://linear.app/developers/sdk)
- [OAuth 2.0 Authentication](https://linear.app/developers/oauth-2-0-authentication)
- [GraphQL API Endpoint](https://linear.app/developers/graphql)
- [Apollo Studio Schema Explorer](https://studio.apollographql.com/public/Linear-API/variant/current/schema/reference)