From 6e7b1091603331dac908312a5d95ca4f875d788d Mon Sep 17 00:00:00 2001 From: Vaibhav Upreti Date: Tue, 31 Dec 2024 13:29:00 +0530 Subject: [PATCH] feat: get userinfo in ssr Signed-off-by: Vaibhav Upreti --- demo/ssr-express-demo/index.js | 19 +++++++++++++------ lib/client.js | 5 +++++ lib/grants/authorization-code.js | 3 +-- lib/grants/pkce-grant.js | 2 ++ lib/grants/refresh-token.js | 2 -- lib/utils/cryptoUtils.js | 13 ++----------- lib/utils/getUserInfo.js | 4 +++- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/demo/ssr-express-demo/index.js b/demo/ssr-express-demo/index.js index 3aa5e9a..33887e7 100644 --- a/demo/ssr-express-demo/index.js +++ b/demo/ssr-express-demo/index.js @@ -218,18 +218,25 @@ app.get('/refresh-token', async (req, res) => { } }); - app.get("/user", async (req, res) => { try { - const cookies = req.cookies; + const accessToken = req.cookies.access_token; + + if (!accessToken) { + return res.status(401).json({ message: "Access token not found. Please authenticate again." }); + } + + // Fetch user information using the access token + const userData = await oauthClient.getUserInfo(accessToken); + res.status(200).json({ - message: "Cookies successfully retrieved", - cookies: cookies, + message: "User information retrieved successfully.", + user: userData, // Assuming `getUserInfo` already returns a parsed object }); } catch (error) { - console.error("Error fetching cookies:", error); + console.error("Error fetching user information:", error); res.status(500).json({ - message: "An error occurred while retrieving cookies", + message: "An error occurred while retrieving user information.", error: error.message, }); } diff --git a/lib/client.js b/lib/client.js index 8f034d0..1942f29 100644 --- a/lib/client.js +++ b/lib/client.js @@ -2,6 +2,7 @@ import { getEnvironment } from './utils/getEnvironment.js'; import { startAuthFlow as browserStartAuthFlow, handleCallback as browserHandleCallback, exchangeAuthCodeForToken as browserExchangeAuthCodeForToken } from './grants/pkce-grant.js'; import { startAuthFlow as serverStartAuthFlow, handleCallback as serverHandleCallback, exchangeAuthCodeForToken as serverExchangeAuthCodeForToken } from './grants/authorization-code.js'; import { refreshAccessToken } from './grants/refresh-token.js'; +import { fetchUserInfo } from './utils/getUserInfo.js'; class OAuthClient { constructor(config, environment = getEnvironment()) { @@ -49,6 +50,10 @@ class OAuthClient { throw new Error(`Unknown environment: ${this.environment}`); } } + + async getUserInfo(accessToken) { + return fetchUserInfo(accessToken); + } } export { OAuthClient }; \ No newline at end of file diff --git a/lib/grants/authorization-code.js b/lib/grants/authorization-code.js index bf7f215..92ad3d4 100644 --- a/lib/grants/authorization-code.js +++ b/lib/grants/authorization-code.js @@ -25,8 +25,7 @@ export async function handleCallback(config) { return null; } const data = response.json(); - return null; - // return exchangeAuthCodeForToken(config); + return data; } export async function exchangeAuthCodeForToken(config, code) { diff --git a/lib/grants/pkce-grant.js b/lib/grants/pkce-grant.js index 6508b82..3bbc230 100644 --- a/lib/grants/pkce-grant.js +++ b/lib/grants/pkce-grant.js @@ -1,3 +1,5 @@ +// For client and native apps + import CryptoUtils from '../utils/cryptoUtils.js'; import { fetchUserInfo } from '../utils/getUserInfo.js' /** diff --git a/lib/grants/refresh-token.js b/lib/grants/refresh-token.js index 3eddbd4..9c31d29 100644 --- a/lib/grants/refresh-token.js +++ b/lib/grants/refresh-token.js @@ -12,7 +12,6 @@ export async function refreshAccessToken(config, refreshToken) { refresh_token: refreshToken, }); - // Make the POST request to refresh the token const response = await fetch(config.token_url, { method: "POST", headers: { @@ -26,7 +25,6 @@ export async function refreshAccessToken(config, refreshToken) { return null; } - // Parse the response to get the tokens const data = await response.json(); // Check if we are in the browser and then store the tokens diff --git a/lib/utils/cryptoUtils.js b/lib/utils/cryptoUtils.js index 3484a7e..a5047d8 100644 --- a/lib/utils/cryptoUtils.js +++ b/lib/utils/cryptoUtils.js @@ -1,22 +1,18 @@ -// Check if we're running in a browser or Node.js const isBrowser = typeof window !== 'undefined'; class CryptoUtils { static generateRandomString(length = 28) { if (isBrowser) { - // Browser: Use the Web Crypto API const array = new Uint32Array(length); window.crypto.getRandomValues(array); return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join(''); } else { - // Node.js: Use the built-in crypto (only available in Node.js) const array = new Uint8Array(length); require('crypto').randomFillSync(array); return Array.from(array, byte => ('0' + byte.toString(16)).substr(-2)).join(''); } } - // Base64 URL encode a buffer (works for both Node.js and browser) static base64urlencode(buffer) { let base64String; if (isBrowser) { @@ -31,30 +27,25 @@ class CryptoUtils { .replace(/=+$/, ''); } - // SHA-256 hashing function (works for both Node.js and browser) static async sha256(plain) { if (isBrowser) { - // Browser: Use the Web Crypto API const encoder = new TextEncoder(); const data = encoder.encode(plain); const hashed = await window.crypto.subtle.digest('SHA-256', data); - return new Uint8Array(hashed); // Convert ArrayBuffer to Uint8Array + return new Uint8Array(hashed); } else { - // Node.js: Use the built-in crypto (only available in Node.js) const crypto = require('crypto'); const hash = crypto.createHash('sha256'); hash.update(plain); - return hash.digest(); // Return a buffer + return hash.digest(); } } - // PKCE challenge generation from a verifier static async pkceChallengeFromVerifier(verifier) { const hashed = await this.sha256(verifier); return this.base64urlencode(hashed); } - // Parse a query string into an object static parseQueryString(query) { const params = new URLSearchParams(query); const result = {}; diff --git a/lib/utils/getUserInfo.js b/lib/utils/getUserInfo.js index 9acf8cc..059628e 100644 --- a/lib/utils/getUserInfo.js +++ b/lib/utils/getUserInfo.js @@ -5,7 +5,7 @@ * @param {string} accessToken - Access token. * @returns {Object|null} - User info if successful, null otherwise. */ -export async function fetchUserInfo(config, accessToken) { +async function fetchUserInfo(config, accessToken) { const baseUrl = new URL(config.token_url).origin; const userInfoUrl = `${baseUrl}/userinfo`; @@ -28,3 +28,5 @@ export async function fetchUserInfo(config, accessToken) { return null; } } + +export {fetchUserInfo}; \ No newline at end of file