UNPKG

x-api-sdk-ts

Version:

TypeScript Library for the X (ex-twitter) API V2

152 lines 5.79 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuth2Auth = void 0; const IOAuth2Auth_1 = require("../interfaces/auth/IOAuth2Auth"); const crypto_1 = __importDefault(require("crypto")); class OAuth2Auth extends IOAuth2Auth_1.AbstractOAuth2Auth { constructor(config, httpAdapter) { super(config, httpAdapter); if (!config.clientId) { throw new Error('OAuth2Auth requires a client ID'); } else if (!this.httpAdapter) { throw new Error('OAuth2Auth requires a httpAdapter'); } this.clientId = config.clientId; this.clientSecret = config.clientSecret; this.redirectUri = config.redirectUri; this.state = config.state || this.generateState(); this.codeVerifier = config.codeVerifier || this.generateCodeVerifier(); this.scopes = config.scopes; this.accessToken = config.accessToken || null; this.refreshToken = config.refreshToken || null; this.tokenExpiresAt = config.tokenExpiresAt || null; } setToken(token) { this.accessToken = token.accessToken; this.refreshToken = token.refreshToken; this.tokenExpiresAt = token.tokenExpiresAt; return this; } getToken() { return { accessToken: this.accessToken, refreshToken: this.refreshToken, tokenExpiresAt: this.tokenExpiresAt, }; } generateAuthorizeUrl(codeChallenge, codeChallengeMethod = 'S256') { if (!codeChallenge) { codeChallengeMethod = 'S256'; codeChallenge = this.generateCodeChallenge(); } const params = new URLSearchParams({ response_type: 'code', client_id: this.clientId, scope: this.scopes.join(' '), state: this.state, code_challenge: codeChallenge, code_challenge_method: codeChallengeMethod, }); if (this.redirectUri) { params.set('redirect_uri', this.redirectUri); } return `https://x.com/i/oauth2/authorize?${params.toString()}`; } async exchangeAuthCodeForToken(code) { const authHeader = 'Basic ' + Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64'); const params = new URLSearchParams({ grant_type: 'authorization_code', code, code_verifier: this.codeVerifier, }); if (this.redirectUri) { params.set('redirect_uri', this.redirectUri); } const response = await this.httpAdapter.fetch('https://api.x.com/2/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': authHeader, }, body: params.toString(), }); if (!response.ok) { const error = await response.text(); throw new Error(`Failed to exchange authorization code: ${error}`); } const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token || null; this.tokenExpiresAt = Date.now() + data.expires_in * 1000; return this; } async getHeaders() { if (!this.accessToken) { throw new Error('No access token available'); } if (this.isTokenExpired() && this.refreshToken) { await this.refreshAccessToken(); } if (!this.accessToken) { throw new Error('Failed to obtain a valid access token'); } return { Authorization: `Bearer ${this.accessToken}`, }; } async refreshAccessToken() { if (!this.refreshToken) { throw new Error('No refresh token available to refresh access token'); } const authHeader = 'Basic ' + Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64'); const response = await this.httpAdapter.fetch('https://api.x.com/2/oauth2/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': authHeader, }, body: new URLSearchParams({ refresh_token: this.refreshToken, grant_type: 'refresh_token', client_id: this.clientId, }), }); if (!response.ok) { const error = await response.text(); throw new Error(`Failed to refresh token: ${error}`); } const data = await response.json(); this.accessToken = data.access_token; this.refreshToken = data.refresh_token || this.refreshToken; this.tokenExpiresAt = Date.now() + data.expires_in * 1000; return this; } isTokenExpired() { if (!this.tokenExpiresAt) { return true; } return Date.now() >= this.tokenExpiresAt; } base64urlEncode(buffer) { return buffer .toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, ''); } generateCodeVerifier() { return this.base64urlEncode(crypto_1.default.randomBytes(32)); } generateCodeChallenge() { return this.base64urlEncode(crypto_1.default.createHash('sha256').update(this.codeVerifier).digest()); } generateState() { return crypto_1.default.randomBytes(16).toString('hex'); } } exports.OAuth2Auth = OAuth2Auth; //# sourceMappingURL=OAuth2Auth.js.map