UNPKG

@manujdhull/nestjs-pkce-oauth2

Version:

A NestJS plugin to simplify OAuth2 PKCE flow integration, including decorators, guards, and token/session management.

105 lines (104 loc) 5.4 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuthController = void 0; const common_1 = require("@nestjs/common"); const token_store_service_1 = require("../services/token-store.service"); const state_guard_1 = require("../guards/state.guard"); const axios_1 = __importDefault(require("axios")); const oauth_initiate_decorator_1 = require("../decorators/oauth-initiate.decorator"); const oauth_callback_decorator_1 = require("../decorators/oauth-callback.decorator"); let OAuthController = class OAuthController { constructor(tokenStore) { this.tokenStore = tokenStore; } async authorize(pkceData, res) { const clientId = process.env.OAUTH_CLIENT_ID; const redirectUri = process.env.OAUTH_REDIRECT_URI; const authUrlBase = process.env.OAUTH_AUTH_URL; if (!clientId || !redirectUri || !authUrlBase) { return res.status(500).send({ error: 'Missing OAuth environment configuration.' }); } const scope = encodeURIComponent('openid email profile'); const responseType = 'code'; const authUrl = `${authUrlBase}?response_type=${responseType}&client_id=${clientId}&redirect_uri=${redirectUri}&code_challenge=${pkceData.codeChallenge}&code_challenge_method=${pkceData.codeChallengeMethod}&state=${pkceData.state}&scope=${scope}&access_type=offline&include_granted_scopes=true`; return res.redirect(authUrl); } async callback(callbackData, codeVerifier, res) { var _a, _b; if (!codeVerifier) { return res.status(400).send({ error: 'Missing code_verifier from frontend.' }); } const tokenUrl = process.env.OAUTH_TOKEN_URL; const redirectUri = process.env.OAUTH_REDIRECT_URI; const clientId = process.env.OAUTH_CLIENT_ID; if (!tokenUrl || !redirectUri || !clientId) { return res.status(500).send({ error: 'Missing OAuth environment configuration.' }); } try { const tokenResponse = await axios_1.default.post(tokenUrl, new URLSearchParams({ code: callbackData.code, grant_type: 'PKCE', redirect_uri: redirectUri, client_id: clientId, code_verifier: codeVerifier, }), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, }); this.tokenStore.set(callbackData.state, tokenResponse.data); return res.send({ message: 'Token received and session stored.' }); } catch (error) { if (axios_1.default.isAxiosError(error)) { console.error('OAuth token exchange failed:', ((_a = error.response) === null || _a === void 0 ? void 0 : _a.data) || error.message); return res.status(500).send({ error: 'Token exchange failed.', details: ((_b = error.response) === null || _b === void 0 ? void 0 : _b.data) || error.message, }); } else { console.error('Unknown error during OAuth callback:', error); return res.status(500).send({ error: 'Unknown error occurred during token exchange.', }); } } } }; exports.OAuthController = OAuthController; __decorate([ (0, common_1.Get)('authorize'), __param(0, (0, oauth_initiate_decorator_1.OAuthInitiate)()), __param(1, (0, common_1.Res)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", Promise) ], OAuthController.prototype, "authorize", null); __decorate([ (0, common_1.UseGuards)(state_guard_1.StateGuard), (0, common_1.Get)('callback'), __param(0, (0, oauth_callback_decorator_1.OAuthCallback)()), __param(1, (0, common_1.Query)('code_verifier')), __param(2, (0, common_1.Res)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, String, Object]), __metadata("design:returntype", Promise) ], OAuthController.prototype, "callback", null); exports.OAuthController = OAuthController = __decorate([ (0, common_1.Controller)('oauth'), __metadata("design:paramtypes", [token_store_service_1.TokenStoreService]) ], OAuthController);