Token导航 LogoToken导航

Agent Skill · 研究检索

oauth2(oauth2 搜索)

用于辅助安全审计、权限检查、凭据风险、认证流程和常见漏洞排查。它适合让 Agent 梳理敏感配置、检查依赖风险、分析鉴权逻辑或生成安全复核清单。使用时不能把工具输出直接当最终结论,涉及密钥、令牌、用户数据或生产系统时,应先确认最小权限、脱敏方式和操作边界。

oauth2 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证为 MIT,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 66,285。

总安装 267周安装 11GitHub Stars 11下载 87核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:oauth2(oauth2 搜索)
来源仓库:https://github.com/oriolrius/pki-manager-web
仓库路径:skills/oauth2
安装命令:
npx skills add https://github.com/oriolrius/pki-manager-web --skill OAuth2
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/oriolrius/pki-manager-web --skill OAuth2

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

用于辅助 OAuth2 相关技术信息检索,适合在 Codex、Claude、Cursor、Gemini CLI 中查找实现方案或最佳实践。可结合关键词与任务场景筛选候选结果,辅助技术选型。通过 npx skills add 命令从指定仓库安装,需参考原始 README 核验具体用法。

安装前建议确认权限范围及是否会触发联网或文件读写操作。oauth2 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/oauth2

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/oriolrius/pki-manager-web --skill OAuth2;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

oauth2 怎么安装?

在终端执行 npx skills add https://github.com/oriolrius/pki-manager-web --skill OAuth2。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

oauth2 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

oauth2 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

oauth2 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

oauth2 用的人多吗?

公开数据是累计安装 267 次,近一周安装 11 次,下载 87 次,GitHub 11 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

oauth2 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 3 个目录同时收录,说明这个 Skill 流传比较广。
  • 许可证明确为 MIT,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
oauth2

oauth2 搜索 · 本页

26711接触敏感数据MIT通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

OAuth 2.0

Expert assistance with OAuth 2.0 authorization framework and OpenID Connect.

Overview

OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts. Key concepts:

  • Resource Owner: User who owns the data
  • Client: Application requesting access
  • Authorization Server: Issues access tokens (e.g., Keycloak, Auth0)
  • Resource Server: API that holds protected resources
  • Access Token: Credentials to access protected resources
  • Refresh Token: Credentials to obtain new access tokens

OAuth 2.0 Flows

Authorization Code Flow (Most Secure)

Best for: Server-side web apps with backend

Flow:

1. Client redirects user to authorization server
   GET /authorize?
     response_type=code
     &client_id=CLIENT_ID
     &redirect_uri=REDIRECT_URI
     &scope=read write
     &state=RANDOM_STATE

2. User authenticates and grants permission

3. Authorization server redirects back with code
   REDIRECT_URI?code=AUTH_CODE&state=RANDOM_STATE

4. Client exchanges code for tokens
   POST /token
   Content-Type: application/x-www-form-urlencoded

   grant_type=authorization_code
   &code=AUTH_CODE
   &redirect_uri=REDIRECT_URI
   &client_id=CLIENT_ID
   &client_secret=CLIENT_SECRET

5. Authorization server responds with tokens
   {
     "access_token": "ACCESS_TOKEN",
     "token_type": "Bearer",
     "expires_in": 3600,
     "refresh_token": "REFRESH_TOKEN",
     "scope": "read write"
   }

Implementation (Node.js):

// Step 1: Redirect to authorization
app.get('/login', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex')
  req.session.oauthState = state

  const authUrl = new URL('https://auth.example.com/authorize')
  authUrl.searchParams.set('response_type', 'code')
  authUrl.searchParams.set('client_id', CLIENT_ID)
  authUrl.searchParams.set('redirect_uri', REDIRECT_URI)
  authUrl.searchParams.set('scope', 'read write')
  authUrl.searchParams.set('state', state)

  res.redirect(authUrl.toString())
})

// Step 3 & 4: Handle callback and exchange code
app.get('/callback', async (req, res) => {
  const { code, state } = req.query

  // Verify state
  if (state !== req.session.oauthState) {
    return res.status(400).send('Invalid state')
  }

  // Exchange code for token
  const tokenResponse = await fetch('https://auth.example.com/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      redirect_uri: REDIRECT_URI,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
    }),
  })

  const tokens = await tokenResponse.json()

  // Store tokens securely
  req.session.accessToken = tokens.access_token
  req.session.refreshToken = tokens.refresh_token

  res.redirect('/dashboard')
})

Authorization Code Flow with PKCE

Best for: Mobile apps, SPAs, any public client

PKCE adds security for public clients that can't keep secrets

Flow:

// Step 1: Generate code verifier and challenge
const codeVerifier = base64URLEncode(crypto.randomBytes(32))
const codeChallenge = base64URLEncode(
  crypto.createHash('sha256').update(codeVerifier).digest()
)

// Step 2: Authorization request
GET /authorize?
  response_type=code
  &client_id=CLIENT_ID
  &redirect_uri=REDIRECT_URI
  &scope=read
  &state=STATE
  &code_challenge=CODE_CHALLENGE
  &code_challenge_method=S256

// Step 3: Token request (no client_secret needed)
POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=REDIRECT_URI
&client_id=CLIENT_ID
&code_verifier=CODE_VERIFIER

Implementation (React):

import { useEffect } from 'react'
import { useRouter } from 'next/router'

// Generate PKCE challenge
function generatePKCE() {
  const codeVerifier = generateRandomString(128)
  const codeChallenge = base64URLEncode(
    sha256(codeVerifier)
  )

  return { codeVerifier, codeChallenge }
}

function LoginButton() {
  const router = useRouter()

  const handleLogin = () => {
    const { codeVerifier, codeChallenge } = generatePKCE()
    const state = generateRandomString(32)

    // Store for later use
    sessionStorage.setItem('pkce_verifier', codeVerifier)
    sessionStorage.setItem('oauth_state', state)

    const authUrl = new URL('https://auth.example.com/authorize')
    authUrl.searchParams.set('response_type', 'code')
    authUrl.searchParams.set('client_id', CLIENT_ID)
    authUrl.searchParams.set('redirect_uri', REDIRECT_URI)
    authUrl.searchParams.set('scope', 'openid profile email')
    authUrl.searchParams.set('state', state)
    authUrl.searchParams.set('code_challenge', codeChallenge)
    authUrl.searchParams.set('code_challenge_method', 'S256')

    window.location.href = authUrl.toString()
  }

  return <button onClick={handleLogin}>Login</button>
}

// Callback page
function CallbackPage() {
  const router = useRouter()

  useEffect(() => {
    async function handleCallback() {
      const { code, state } = router.query

      // Verify state
      const savedState = sessionStorage.getItem('oauth_state')
      if (state !== savedState) {
        throw new Error('Invalid state')
      }

      // Get code verifier
      const codeVerifier = sessionStorage.getItem('pkce_verifier')

      // Exchange code for token
      const response = await fetch('https://auth.example.com/token', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: new URLSearchParams({
          grant_type: 'authorization_code',
          code: code as string,
          redirect_uri: REDIRECT_URI,
          client_id: CLIENT_ID,
          code_verifier: codeVerifier!,
        }),
      })

      const tokens = await response.json()

      // Store tokens
      localStorage.setItem('access_token', tokens.access_token)
      localStorage.setItem('refresh_token', tokens.refresh_token)

      // Clean up
      sessionStorage.removeItem('pkce_verifier')
      sessionStorage.removeItem('oauth_state')

      router.push('/dashboard')
    }

    handleCallback()
  }, [router.query])

  return <div>Logging in...</div>
}

Client Credentials Flow

Best for: Machine-to-machine, service accounts, server-to-server

Flow:

# Request token
POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&scope=api.read api.write

# Response
{
  "access_token": "ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "api.read api.write"
}

Implementation:

async function getServiceToken() {
  const response = await fetch('https://auth.example.com/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'client_credentials',
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET,
      scope: 'api.read api.write',
    }),
  })

  return await response.json()
}

// Use token
async function callProtectedAPI() {
  const { access_token } = await getServiceToken()

  const response = await fetch('https://api.example.com/data', {
    headers: {
      'Authorization': `Bearer ${access_token}`,
    },
  })

  return await response.json()
}

Resource Owner Password Credentials (Legacy)

⚠️ Not recommended - Only use when no other flow works

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=password
&username=USER
&password=PASSWORD
&client_id=CLIENT_ID
&client_secret=CLIENT_SECRET
&scope=read

Implicit Flow (Deprecated)

⚠️ Deprecated - Use Authorization Code Flow with PKCE instead

Token Management

Access Tokens

Characteristics:

  • Short-lived (5-15 minutes typical)
  • Used to access protected resources
  • Should be treated as opaque strings
  • Often JWT format but not required

Usage:

// Make API request with access token
fetch('https://api.example.com/user/profile', {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
  },
})

Refresh Tokens

Purpose: Obtain new access tokens without re-authentication

Usage:

async function refreshAccessToken(refreshToken) {
  const response = await fetch('https://auth.example.com/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
    }),
  })

  const tokens = await response.json()
  return tokens
}

// Automatic token refresh
async function apiCall(url, options = {}) {
  let accessToken = localStorage.getItem('access_token')

  let response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${accessToken}`,
    },
  })

  // Token expired
  if (response.status === 401) {
    const refreshToken = localStorage.getItem('refresh_token')
    const newTokens = await refreshAccessToken(refreshToken)

    localStorage.setItem('access_token', newTokens.access_token)
    if (newTokens.refresh_token) {
      localStorage.setItem('refresh_token', newTokens.refresh_token)
    }

    // Retry request with new token
    response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        'Authorization': `Bearer ${newTokens.access_token}`,
      },
    })
  }

  return response
}

Token Storage

Best Practices:

Browser (SPA):

  • ✅ Memory (most secure, lost on refresh)
  • ✅ Session storage (cleared on tab close)
  • ⚠️ Local storage (XSS risk, but convenient)
  • ❌ Cookies without httpOnly (XSS risk)
  • ✅ httpOnly cookies (CSRF protection needed)

Server-side:

  • ✅ Encrypted session storage
  • ✅ Secure database with encryption
  • ❌ Plain text files
  • ❌ Environment variables (for user tokens)

Implementation:

// Secure token storage (Next.js)
import { serialize, parse } from 'cookie'

// Set token in httpOnly cookie
export function setTokenCookie(res, token) {
  const cookie = serialize('token', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    maxAge: 3600,
    path: '/',
  })

  res.setHeader('Set-Cookie', cookie)
}

// Get token from cookie
export function getTokenCookie(req) {
  const cookies = parse(req.headers.cookie || '')
  return cookies.token
}

OpenID Connect (OIDC)

OAuth 2.0 extension for authentication

ID Token

JWT containing user information:

{
  "iss": "https://auth.example.com",
  "sub": "user-123",
  "aud": "client-id",
  "exp": 1234567890,
  "iat": 1234567890,
  "name": "John Doe",
  "email": "john@example.com",
  "email_verified": true,
  "picture": "https://example.com/photo.jpg"
}

OIDC Flow

// Authorization request with openid scope
GET /authorize?
  response_type=code
  &client_id=CLIENT_ID
  &redirect_uri=REDIRECT_URI
  &scope=openid profile email
  &state=STATE

// Token response includes ID token
{
  "access_token": "ACCESS_TOKEN",
  "id_token": "ID_TOKEN_JWT",
  "refresh_token": "REFRESH_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600
}

// Validate ID token
import jwt from 'jsonwebtoken'
import jwksClient from 'jwks-rsa'

const client = jwksClient({
  jwksUri: 'https://auth.example.com/.well-known/jwks.json'
})

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    const signingKey = key.publicKey || key.rsaPublicKey
    callback(null, signingKey)
  })
}

jwt.verify(idToken, getKey, {
  audience: CLIENT_ID,
  issuer: 'https://auth.example.com',
  algorithms: ['RS256']
}, (err, decoded) => {
  if (err) {
    console.error('Invalid token')
  } else {
    console.log('User:', decoded)
  }
})

UserInfo Endpoint

// Get additional user info
async function getUserInfo(accessToken) {
  const response = await fetch('https://auth.example.com/userinfo', {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  })

  return await response.json()
}

Discovery

# Get provider configuration
GET https://auth.example.com/.well-known/openid-configuration

# Response includes:
{
  "issuer": "https://auth.example.com",
  "authorization_endpoint": "https://auth.example.com/authorize",
  "token_endpoint": "https://auth.example.com/token",
  "userinfo_endpoint": "https://auth.example.com/userinfo",
  "jwks_uri": "https://auth.example.com/.well-known/jwks.json",
  "response_types_supported": ["code", "token", "id_token"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"]
}

Scopes

Standard Scopes

  • openid - Required for OIDC
  • profile - User's profile info (name, picture, etc.)
  • email - User's email address
  • address - User's address
  • phone - User's phone number
  • offline_access - Request refresh token

Custom Scopes

API-specific permissions:
- api:read - Read access to API
- api:write - Write access to API
- api:delete - Delete access to API
- admin - Admin access

Requesting Scopes

// Request multiple scopes
const authUrl = new URL('https://auth.example.com/authorize')
authUrl.searchParams.set('scope', 'openid profile email api:read api:write')

Security Best Practices

1. Always Use State Parameter

// Generate random state
const state = crypto.randomBytes(32).toString('hex')
sessionStorage.setItem('oauth_state', state)

// Include in authorization request
authUrl.searchParams.set('state', state)

// Verify in callback
if (receivedState !== sessionStorage.getItem('oauth_state')) {
  throw new Error('CSRF attack detected')
}

2. Use PKCE for Public Clients

Always use PKCE for SPAs and mobile apps - no exceptions.

3. Validate Tokens

// Validate JWT
- Verify signature using public key
- Check issuer (iss)
- Check audience (aud)
- Check expiration (exp)
- Check not before (nbf)

4. Short-Lived Access Tokens

Access token: 5-15 minutes
Refresh token: Days to months (with rotation)

5. Token Rotation

// Refresh token rotation
When using refresh token:
1. Issue new access token
2. Issue new refresh token
3. Invalidate old refresh token

6. Secure Token Storage

// ✅ Best practices
- httpOnly cookies (server-side)
- Encrypted session storage (server-side)
- Memory only (SPA, lost on refresh)

// ❌ Avoid
- Local storage (XSS vulnerable)
- Session storage without proper sanitization
- URL parameters
- Plain text anywhere

7. Redirect URI Validation

// Server must validate exact match
Registered: https://app.example.com/callback
Valid:     https://app.example.com/callback
Invalid:   https://app.example.com/callback/extra
Invalid:   https://evil.com/callback

8. HTTPS Only

All OAuth communication must use HTTPS in production.

9. Rate Limiting

Implement rate limiting on:

  • Token endpoint
  • Authorization endpoint
  • UserInfo endpoint

10. Audit Logging

Log all OAuth events:

  • Authorization requests
  • Token issuances
  • Token refreshes
  • Failed attempts

Common Patterns

API Protection

// Express middleware
function requireAuth(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1]

  if (!token) {
    return res.status(401).json({ error: 'No token provided' })
  }

  try {
    const decoded = jwt.verify(token, PUBLIC_KEY)
    req.user = decoded
    next()
  } catch (error) {
    return res.status(401).json({ error: 'Invalid token' })
  }
}

// Protected route
app.get('/api/protected', requireAuth, (req, res) => {
  res.json({ data: 'Protected data', user: req.user })
})

// Role-based protection
function requireRole(role) {
  return (req, res, next) => {
    if (!req.user?.roles?.includes(role)) {
      return res.status(403).json({ error: 'Insufficient permissions' })
    }
    next()
  }
}

app.delete('/api/users/:id', requireAuth, requireRole('admin'), (req, res) => {
  // Delete user
})

Silent Authentication

// Attempt silent authentication in hidden iframe
function silentAuthentication() {
  return new Promise((resolve, reject) => {
    const iframe = document.createElement('iframe')
    iframe.style.display = 'none'

    const authUrl = new URL('https://auth.example.com/authorize')
    authUrl.searchParams.set('prompt', 'none')
    authUrl.searchParams.set('response_type', 'code')
    authUrl.searchParams.set('client_id', CLIENT_ID)
    authUrl.searchParams.set('redirect_uri', SILENT_REDIRECT_URI)

    iframe.src = authUrl.toString()

    window.addEventListener('message', (event) => {
      if (event.origin !== 'https://app.example.com') return

      if (event.data.code) {
        resolve(event.data.code)
      } else {
        reject(new Error('Silent auth failed'))
      }

      document.body.removeChild(iframe)
    })

    document.body.appendChild(iframe)
  })
}

Troubleshooting

Invalid Grant

  • Expired authorization code
  • Code already used
  • Mismatched redirect URI
  • Invalid code verifier (PKCE)

Invalid Client

  • Wrong client credentials
  • Client not found
  • Client disabled

Unauthorized Client

  • Client not allowed for grant type
  • Client not allowed for scope

Access Denied

  • User denied permission
  • Invalid scope requested

Resources

平台分布

Claude Code

31.22%
按下载量换算27

Antigravity

22.15%
按下载量换算19

windsurf

17.36%
按下载量换算15

trae

14.78%
按下载量换算13

Codex

9.07%
按下载量换算8

OpenCode

3.71%
按下载量换算3

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

继续浏览同类 Skills