К основному содержанию
скилл CX Codex

oauth-implementation · mindrally — скилл для Claude Code

Инструкции по настройке OAuth 2.0 и 2.1 с защитой через PKCE, ротацией токенов и валидацией redirect URI. Помогает внедрить авторизацию без устаревших небезопасных потоков.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add Mindrally/skills --skill oauth-implementation -a claude-code
Открыть на GitHub

Что делает oauth-implementation

Скилл передаёт агенту правила реализации протоколов OAuth 2.0 и OAuth 2.1. Он исключает небезопасные сценарии: Implicit grant и Resource Owner Password Credentials. Вместо них для всех клиентов запускается Authorization Code Flow с обязательной генерацией параметров PKCE. Код создаёт криптографический верификатор code_verifier и хеш code_challenge на базе SHA-256.

На сервере выполняется валидация параметров state для защиты от CSRF. Скилл требует точного совпадения Redirect URI со списком разрешённых адресов. Подстановочные знаки запрещены. Для сессий применяется ротация Refresh-токенов.

Для проверки подписи JWT в серверном примере требуются пакеты jsonwebtoken и jwks-rsa.

Какие задачи решает

  • настроить Authorization Code Flow с PKCE на клиенте
  • валидировать токены JWT через JWKS на Node.js
  • реализовать ротацию refresh-токенов для обновления сессий
  • защитить процесс авторизации от CSRF через параметр state

Примеры запросов агенту

  • Напиши функцию авторизации через OAuth 2.1 с генерацией параметров PKCE
  • Реализуй серверный обработчик /oauth/callback с обменом кода на токены в Express
  • Добавь валидацию access-токена через JWKS с проверкой алгоритма RS256

Как установить oauth-implementation

1Через Skills CLI (Vercel)

npx skills add Mindrally/skills --skill oauth-implementation -a claude-code

2Вручную: положить файлы

~/.claude/skills/oauth-implementation/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/oauth-implementation/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о oauth-implementation

Как установить oauth-implementation в Claude Code?

Выполните команду npx skills add Mindrally/skills --skill oauth-implementation -a claude-code. Также можно вручную сохранить файл по пути ~/.claude/skills/oauth-implementation/SKILL.md.

Какие потоки авторизации исключает этот скилл?

Скилл запрещает Implicit grant и Resource Owner Password Credentials из-за требований OAuth 2.1. Вместо них применяется только Authorization Code Flow с обязательным PKCE.

Какие зависимости нужны для проверки JWT на сервере?

В серверном примере валидация токенов построена на библиотеках jsonwebtoken и jwks-rsa с белым списком для алгоритма RS256.

Исходный текст

SKILL.md · Apache-2.0
---
name: oauth-implementation
description: Guidelines for implementing OAuth 2.0 and OAuth 2.1 authentication flows with security best practices and PKCE
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# OAuth Implementation

You are an expert in OAuth 2.0 and OAuth 2.1 implementation. Follow these guidelines when implementing OAuth authentication flows.

## Core Principles

- Always use OAuth 2.1 patterns (PKCE required, no implicit flow)
- Use HTTPS for all OAuth communications
- Implement proper state management for CSRF protection
- Follow the principle of least privilege for scopes
- Validate all tokens server-side

## OAuth 2.1 Key Requirements

OAuth 2.1 consolidates best practices and deprecates insecure patterns:

- PKCE is required for ALL clients using authorization code flow
- Implicit grant is removed
- Resource Owner Password Credentials grant is removed
- Redirect URIs must use exact string matching
- Refresh tokens must be sender-constrained or use rotation

## Authorization Code Flow with PKCE

### Step 1: Generate PKCE Parameters

```javascript
// Generate cryptographically secure code verifier
function generateCodeVerifier() {
  const array = new Uint8Array(32);
  crypto.getRandomValues(array);
  return base64URLEncode(array);
}

// Create code challenge from verifier
async function generateCodeChallenge(verifier) {
  const encoder = new TextEncoder();
  const data = encoder.encode(verifier);
  const digest = await crypto.subtle.digest('SHA-256', data);
  return base64URLEncode(new Uint8Array(digest));
}

function base64URLEncode(buffer) {
  return btoa(String.fromCharCode(...buffer))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}
```

### Step 2: Authorization Request

```javascript
async function initiateOAuthFlow() {
  const codeVerifier = generateCodeVerifier();
  const codeChallenge = await generateCodeChallenge(codeVerifier);
  const state = generateSecureRandomString();

  // Store for later verification
  sessionStorage.setItem('oauth_code_verifier', codeVerifier);
  sessionStorage.setItem('oauth_state', state);

  const params = new URLSearchParams({
    response_type: 'code',
    client_id: CLIENT_ID,
    redirect_uri: REDIRECT_URI,
    scope: 'openid profile email',
    state: state,
    code_challenge: codeChallenge,
    code_challenge_method: 'S256',
  });

  window.location.href = `${AUTHORIZATION_ENDPOINT}?${params}`;
}
```

### Step 3: Handle Callback and Token Exchange

```javascript
async function handleCallback() {
  const params = new URLSearchParams(window.location.search);
  const code = params.get('code');
  const state = params.get('state');
  const error = params.get('error');

  // Check for errors
  if (error) {
    throw new Error(`OAuth error: ${error} - ${params.get('error_description')}`);
  }

  // Validate state to prevent CSRF
  const storedState = sessionStorage.getItem('oauth_state');
  if (state !== storedState) {
    throw new Error('Invalid state parameter - possible CSRF attack');
  }

  // Retrieve code verifier
  const codeVerifier = sessionStorage.getItem('oauth_code_verifier');

  // Exchange code for tokens
  const response = await fetch(TOKEN_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: REDIRECT_URI,
      client_id: CLIENT_ID,
      code_verifier: codeVerifier,
    }),
  });

  if (!response.ok) {
    throw new Error('Token exchange failed');
  }

  const tokens = await response.json();

  // Clean up
  sessionStorage.removeItem('oauth_code_verifier');
  sessionStorage.removeItem('oauth_state');

  return tokens;
}
```

## Server-Side Implementation

### Confidential Client Token Exchange

```javascript
// Node.js/Express example
app.post('/oauth/callback', async (req, res) => {
  const { code, state } = req.body;

  // Validate state
  if (state !== req.session.oauthState) {
    return res.status(400).json({ error: 'Invalid state' });
  }

  try {
    const tokenResponse = await fetch(TOKEN_ENDPOINT, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        // Client authentication for confidential clients
        Authorization: `Basic ${Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString('base64')}`,
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        code: code,
        redirect_uri: REDIRECT_URI,
        code_verifier: req.session.codeVerifier,
      }),
    });

    const tokens = await tokenResponse.json();

    // Store tokens securely server-side
    req.session.accessToken = tokens.access_token;
    req.session.refreshToken = tokens.refresh_token;

    res.redirect('/dashboard');
  } catch (error) {
    res.status(500).json({ error: 'Token exchange failed' });
  }
});
```

## Token Security Best Practices

### Access Token Validation

```javascript
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
  jwksUri: `${ISSUER}/.well-known/jwks.json`,
  cache: true,
  cacheMaxAge: 600000, // 10 minutes
});

function getSigningKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) return callback(err);
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

async function validateToken(token) {
  return new Promise((resolve, reject) => {
    jwt.verify(
      token,
      getSigningKey,
      {
        audience: EXPECTED_AUDIENCE,
        issuer: EXPECTED_ISSUER,
        algorithms: ['RS256'], // Whitelist allowed algorithms
      },
      (err, decoded) => {
        if (err) reject(err);
        else resolve(decoded);
      }
    );
  });
}
```

### Refresh Token Rotation

```javascript
async function refreshAccessToken(refreshToken) {
  const response = await fetch(TOKEN_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: CLIENT_ID,
    }),
  });

  if (!response.ok) {
    // Refresh token may be expired or revoked
    throw new Error('Refresh token invalid');
  }

  const tokens = await response.json();

  // If rotation is enabled, you'll receive a new refresh token
  // Store the new refresh token and invalidate the old one
  return tokens;
}
```

## Security Requirements

### Redirect URI Validation

```javascript
// Server-side: validate redirect URIs against whitelist
const ALLOWED_REDIRECT_URIS = [
  'https://myapp.com/callback',
  'https://myapp.com/oauth/callback',
];

function validateRedirectUri(uri) {
  // Exact string matching - no wildcards
  return ALLOWED_REDIRECT_URIS.includes(uri);
}
```

### Scope Management

```javascript
// Request minimum necessary scopes
const SCOPES = {
  basic: 'openid profile email',
  readOnly: 'openid profile email read:data',
  fullAccess: 'openid profile email read:data write:data',
};

// Validate scopes on the server
function validateScopes(requestedScopes, allowedScopes) {
  const requested = requestedScopes.split(' ');
  const allowed = allowedScopes.split(' ');
  return requested.every(scope => allowed.includes(scope));
}
```

## Common Vulnerabilities to Prevent

### 1. Authorization Code Injection

Always use PKCE - the code_verifier ensures only the original requester can exchange the code.

### 2. CSRF Attacks

```javascript
// Always use and validate the state parameter
const state = crypto.randomBytes(32).toString('hex');
// Store in session and validate on callback
```

### 3. Open Redirect

```javascript
// Never construct redirect URIs from user input
// Always use whitelisted URIs
const redirectUri = ALLOWED_REDIRECT_URIS[0]; // Don't: req.query.redirect_uri
```

### 4. Token Leakage

```javascript
// Never log tokens
console.log('User authenticated'); // Good
console.log(`Token: ${accessToken}`); // NEVER DO THIS

// Don't include tokens in URLs
// Use Authorization header instead
fetch('/api/resource', {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});
```

## Token Storage Recommendations

### Browser Applications

```javascript
// Option 1: Memory (most secure, but lost on refresh)
let accessToken = null;

// Option 2: HttpOnly cookies (requires backend)
// Set by server with appropriate flags
// Secure, HttpOnly, SameSite=Strict

// Option 3: sessionStorage (cleared when tab closes)
sessionStorage.setItem('access_token', token);

// Avoid localStorage for sensitive tokens
// Vulnerable to XSS attacks
```

### Server Applications

```javascript
// Store tokens encrypted in session or database
const encryptedToken = encrypt(accessToken, SESSION_ENCRYPTION_KEY);
req.session.encryptedAccessToken = encryptedToken;
```

## Error Handling

```javascript
const OAUTH_ERRORS = {
  invalid_request: 'The request is missing a required parameter',
  unauthorized_client: 'The client is not authorized',
  access_denied: 'The user denied the request',
  unsupported_response_type: 'The response type is not supported',
  invalid_scope: 'The requested scope is invalid',
  server_error: 'The authorization server encountered an error',
  temporarily_unavailable: 'The server is temporarily unavailable',
};

function handleOAuthError(error, errorDescription) {
  const message = OAUTH_ERRORS[error] || 'Unknown error';
  console.error(`OAuth Error: ${message}. Details: ${errorDescription}`);
  // Show user-friendly error message
}
```

## Testing Checklist

- [ ] PKCE flow works correctly
- [ ] State parameter is validated
- [ ] Invalid state is rejected
- [ ] Token expiration is handled
- [ ] Refresh token rotation works
- [ ] Invalid tokens are rejected
- [ ] Scopes are properly enforced
- [ ] Redirect URIs are validated
- [ ] Error cases are handled gracefully

© Mindrally · Apache-2.0 · Mindrally/skills

Похожие скиллы

Все скиллы по теме «Безопасность» →

Сначала — oauth-implementation от других авторов.

oauth-implementation aj-geddes Помогает развернуть потоки OAuth 2.0, OpenID Connect, авторизацию по JWT и SSO в веб- и мобильных проектах. Пригодится при настройке входа через соцсети и защите API. CX Codex +1 553установок git-guardrails-claude-code Matt Pocock Скилл ставит хук Claude Code, который останавливает опасные Git-команды до их запуска. Нужен, если агент не должен делать push или удалять изменения. 499 069установок ponytail-review DietrichGebert Скилл проверяет изменения глубже обычного diff: читает связанный код, ищет ошибки, риски, проблемы нагрузки и недостающие тесты. Пригодится для ревью PR и коммитов. CX Codex +1 57 000установок ponytail-audit DietrichGebert Проверяет репозиторий и ранжирует ошибки, риски и лишний код. Подойдёт, если нужен разовый разбор без автоматических правок. CX Codex +1 45 400установок security-audit cloudflare Проверяет кодовую базу на уязвимости и ищет нарушения границ доверия. Пригодится перед релизом или для точечного разбора опасных участков кода. CX Codex +1 54 800установок security-and-hardening addyosmani Помогает проектировать защиту и проверять код на уязвимости при работе с вводом, авторизацией, сессиями и внешними сервисами. Подойдёт перед релизом и при создании функций, которые обрабатывают недоверенные данные. CX Codex +1 70 200установок supabase официальный supabase Скилл помогает настраивать базу данных, аутентификацию и RLS в Supabase без скрытых дыр в безопасности. CX Codex GP ChatGPT 8установок

Из того же набора214

phoenix Задаёт агенту правила кода на Elixir и Phoenix: LiveView, Ecto, контексты, тесты. Пригодится, когда проект уже на Phoenix и нужен предсказуемый стиль. CX Codex +1 722установок sveltekit Скилл задаёт правила разработки на SvelteKit с TypeScript и Tailwind CSS. Помогает писать серверные функции загрузки, формы и статические страницы. CX Codex +1 720установок solidity Скилл для написания и ревью Solidity-контрактов: паттерны защиты от reentrancy, оптимизация gas, тесты и связка с React-фронтендом. CX Codex +1 721установок autogen-development Подсказывает агенту, как писать код на Microsoft AutoGen: создание агентов, групповые чаты, инструменты, оркестрация. CX Codex +1 721установок figma-integration Направляет ИИ-агента при переносе макетов из Figma в код: от разбора токенов и стилей до настройки MCP-серверов. Помогает сохранить сетку, типографику и состояния компонентов. CX Codex +1 718установок vercel-development Набор правил для ИИ-агента: как писать код под Next.js App Router, React Server Components и Vercel AI SDK. Пригодится, когда агент лепит клиентские компоненты там, где хватило бы серверных. CX Codex +1 712установок rest-api-django Набор правил для ИИ-агента, который пишет Django REST API: структура проекта, сериализаторы, JWT-аутентификация, борьба с N+1. CX Codex +1 712установок postcss-best-practices Скилл с рекомендациями по настройке PostCSS, сжатию стилей через cssnano и интеграции с Vite, Webpack и Next.js. CX Codex +1 710установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой