Cliente OAuth para TypeScript: implementação de autorização em site educacional
\n\nNo desenvolvimento web moderno, o OAuth (Open Authorization) tornou-se o padrão de facto para autenticação de usuários através de serviços terceiros. Para o site educacional pythonlib.ru, preparamos a descrição de um cliente OAuth universal em TypeScript, que permite implementar login via GitHub, Google e outros provedores populares.
\n\nO que é um cliente OAuth?
\nUm cliente OAuth é um componente de software que gerencia o processo de obtenção de permissões do usuário para acessar seus dados em um serviço terceiro. No contexto do TypeScript, esse cliente geralmente implementa o protocolo OAuth 2.0 e inclui:
\n- \n
- Inicialização do processo de autorização \n
- Processamento de requisições de callback \n
- Troca do authorization code por access token \n
- Atualização de tokens (refresh token) \n
- Gerenciamento do estado da sessão \n
Arquitetura do cliente OAuth em TypeScript
\nNosso cliente é construído com base nos princípios de modularidade e segurança de tipos. Componentes principais:
\n\n1. Configuração do provedor
\ninterface OAuthProviderConfig {\n clientId: string;\n clientSecret: string;\n redirectUri: string;\n authorizationEndpoint: string;\n tokenEndpoint: string;\n scopes: string[];\n}\n\nconst githubConfig: OAuthProviderConfig = {\n clientId: process.env.GITHUB_CLIENT_ID!,\n clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n redirectUri: 'https://pythonlib.ru/auth/callback/github',\n authorizationEndpoint: 'https://github.com/login/oauth/authorize',\n tokenEndpoint: 'https://github.com/login/oauth/access_token',\n scopes: ['read:user', 'user:email']\n};\n\n2. Geração da URL de autorização
\nfunction generateAuthUrl(config: OAuthProviderConfig, state: string): string {\n const params = new URLSearchParams({\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n scope: config.scopes.join(' '),\n state: state,\n response_type: 'code'\n });\n \n return `${config.authorizationEndpoint}?${params.toString()}`;\n}\n\n3. Troca do código por token
\nasync function exchangeCodeForToken(\n config: OAuthProviderConfig,\n code: string\n): Promise<OAuthTokenResponse> {\n const response = await fetch(config.tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json'\n },\n body: JSON.stringify({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n code: code,\n redirect_uri: config.redirectUri\n })\n });\n\n if (!response.ok) {\n throw new Error(`Token exchange failed: ${response.statusText}`);\n }\n\n return response.json();\n}\n\nTrabalhando com tokens
\nApós obter os tokens, é necessário garantir seu armazenamento e atualização seguros. Recomenda-se o uso de cookies httpOnly ou armazenamento de sessão no servidor.
\n\nAtualização do access token
\nasync function refreshAccessToken(\n config: OAuthProviderConfig,\n refreshToken: string\n): Promise<OAuthTokenResponse> {\n const response = await fetch(config.tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n client_id: config.clientId,\n client_secret: config.clientSecret,\n refresh_token: refreshToken,\n grant_type: 'refresh_token'\n })\n });\n\n return response.json();\n}\n\nExemplo completo de implementação para GitHub OAuth
\nimport { randomBytes } from 'crypto';\n\nclass GitHubOAuthClient {\n private config: OAuthProviderConfig;\n private stateStore: Map<string, string> = new Map();\n\n constructor() {\n this.config = {\n clientId: process.env.GITHUB_CLIENT_ID!,\n clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n redirec