UNPKG

oauth-entra-id

Version:

🛡️ A Secure, Performant, and Feature-Rich OAuth 2.0 Integration for Microsoft Entra ID — Fully Abstracted and Production-Ready.

151 lines (148 loc) 7.19 kB
'use strict'; var chunk7MTPXR5V_cjs = require('./chunk-7MTPXR5V.cjs'); var modernCookies = require('modern-cookies'); async function $sharedHandleAuthentication(req, res) { const body = req.body; const params = body ? { loginPrompt: body.loginPrompt, email: body.email, frontendUrl: body.frontendUrl, azureId: body.azureId } : {}; const { authUrl } = await req.oauthProvider.getAuthUrl(params); res.status(200).json({ url: authUrl }); } async function $sharedHandleCallback(req, res) { const body = req.body; if (!body) throw new chunk7MTPXR5V_cjs.OAuthError({ msg: "Invalid params", desc: "Body must contain code and state" }); const { accessToken, refreshToken, frontendUrl } = await req.oauthProvider.getTokenByCode({ code: body.code, state: body.state }); modernCookies.setCookie(res, accessToken.name, accessToken.value, accessToken.options); if (refreshToken) modernCookies.setCookie(res, refreshToken.name, refreshToken.value, refreshToken.options); res.redirect(303, frontendUrl); } async function $sharedHandleLogout(req, res) { const body = req.body; const params = body ? { frontendUrl: body.frontendUrl, azureId: body.azureId } : {}; const { logoutUrl, deleteAccessToken, deleteRefreshToken } = await req.oauthProvider.getLogoutUrl(params); modernCookies.deleteCookie(res, deleteRefreshToken.name, deleteRefreshToken.options); modernCookies.deleteCookie(res, deleteAccessToken.name, deleteAccessToken.options); res.status(200).json({ url: logoutUrl }); } async function $sharedHandleOnBehalfOf(req, res) { const body = req.body; if (!body) throw new chunk7MTPXR5V_cjs.OAuthError({ msg: "Invalid params", desc: "Body must contain serviceNames" }); if (!req.accessTokenInfo?.jwt) { throw new chunk7MTPXR5V_cjs.OAuthError({ msg: "Unauthorized", desc: "Access token is required for on-behalf-of requests", status: 401 }); } if (req.userInfo?.isApp === true) { throw new chunk7MTPXR5V_cjs.OAuthError({ msg: "Forbidden", desc: "On-behalf-of requests are not allowed for app users", status: 403 }); } const { results } = await req.oauthProvider.getTokenOnBehalfOf({ services: body.services, accessToken: req.accessTokenInfo.jwt, azureId: body.azureId }); for (const { accessToken } of results) { modernCookies.setCookie(res, accessToken.name, accessToken.value, accessToken.options); } res.status(200).json({ tokensSet: results.length }); } async function $sharedMiddleware(req, res) { const b2b = await $checkB2BToken(req); if (b2b.error) throw new chunk7MTPXR5V_cjs.OAuthError(b2b.error); if (b2b.userInfo) { return { userInfo: b2b.userInfo, tryInjectData: (_data) => Promise.resolve( chunk7MTPXR5V_cjs.$err({ msg: "Invalid user type", desc: "Injecting data is only supported for user-based sessions" }) ) }; } const injectFunc = $createInjectFunc(req, res); const { cookies } = req.oauthProvider.settings; let firstError = null; for (const { accessTokenName, refreshTokenName } of cookies.cookieNames) { const cookie = await $checkCookieTokens(req, res, injectFunc, accessTokenName, refreshTokenName); if (cookie.error) { if (!firstError) firstError = cookie.error; continue; } for (const { azureId, accessTokenName: accessTokenName2, refreshTokenName: refreshTokenName2 } of cookies.cookieNames) { if (azureId === cookie.userInfo.azureId) continue; modernCookies.deleteCookie(res, accessTokenName2, cookies.deleteOptions); modernCookies.deleteCookie(res, refreshTokenName2, cookies.deleteOptions); } return { userInfo: cookie.userInfo, tryInjectData: cookie.tryInjectData }; } throw new chunk7MTPXR5V_cjs.OAuthError(firstError ?? chunk7MTPXR5V_cjs.$err({ msg: "Unauthorized", desc: "Tokens are invalid or missing", status: 401 })); } function $createInjectFunc(req, res) { return async (accessToken, data) => { const inj = await req.oauthProvider.tryInjectData({ accessToken, data }); if (inj.error) return chunk7MTPXR5V_cjs.$err(inj.error); if (req.userInfo?.isApp !== false) { return chunk7MTPXR5V_cjs.$err({ msg: "Invalid user type", desc: "Injecting data is only supported for user-based sessions" }); } modernCookies.setCookie(res, inj.newAccessToken.name, inj.newAccessToken.value, inj.newAccessToken.options); req.userInfo = { ...req.userInfo, injectedData: data }; return chunk7MTPXR5V_cjs.$ok({ injectedData: data }); }; } async function $checkB2BToken(req) { const authHeader = req.headers.authorization; if (!req.oauthProvider.settings.acceptB2BRequests || !authHeader) return chunk7MTPXR5V_cjs.$ok({ userInfo: void 0 }); const token = authHeader.startsWith("Bearer ") ? authHeader.split(" ")[1] : void 0; const bearer = await req.oauthProvider.verifyAccessToken(token); if (bearer.error) return chunk7MTPXR5V_cjs.$err(bearer.error); return chunk7MTPXR5V_cjs.$ok({ userInfo: $userInfo(req, bearer.meta, bearer.rawJwt, bearer.payload) }); } async function $checkCookieTokens(req, res, injectFunc, accessTokenName, refreshTokenName) { const accessToken = modernCookies.getCookie(req, accessTokenName); const refreshToken = modernCookies.getCookie(req, refreshTokenName); if (!accessToken && !refreshToken) { return chunk7MTPXR5V_cjs.$err({ msg: "Unauthorized", desc: "Access token and refresh token are both missing", status: 401 }); } const at = await req.oauthProvider.verifyAccessToken(accessToken); if (at.error && !refreshToken) return chunk7MTPXR5V_cjs.$err(at.error); if (at.success) { return chunk7MTPXR5V_cjs.$ok({ azureId: at.meta.azureId, userInfo: $userInfo(req, at.meta, at.rawJwt, at.payload, at.injectedData), tryInjectData: (data) => injectFunc(at.rawJwt, data) }); } const rt = await req.oauthProvider.tryRefreshTokens(refreshToken); if (rt.error) return chunk7MTPXR5V_cjs.$err(rt.error); modernCookies.setCookie(res, rt.newAccessToken.name, rt.newAccessToken.value, rt.newAccessToken.options); if (rt.newRefreshToken) modernCookies.setCookie(res, rt.newRefreshToken.name, rt.newRefreshToken.value, rt.newRefreshToken.options); return chunk7MTPXR5V_cjs.$ok({ azureId: rt.meta.azureId, userInfo: $userInfo(req, rt.meta, rt.rawJwt, rt.payload), tryInjectData: (data) => injectFunc(rt.rawJwt, data) }); } function $userInfo(req, meta, rawJwt, payload, injectedData) { const userInfo = { azureId: meta.azureId, tenantId: meta.tenantId, uniqueId: meta.uniqueId, roles: meta.roles, ...meta.isApp ? { isApp: true, appId: meta.appId } : { isApp: false, name: meta.name, email: meta.email, injectedData } }; req.userInfo = userInfo; req.accessTokenInfo = { jwt: rawJwt, payload, meta }; return userInfo; } exports.$sharedHandleAuthentication = $sharedHandleAuthentication; exports.$sharedHandleCallback = $sharedHandleCallback; exports.$sharedHandleLogout = $sharedHandleLogout; exports.$sharedHandleOnBehalfOf = $sharedHandleOnBehalfOf; exports.$sharedMiddleware = $sharedMiddleware; //# sourceMappingURL=chunk-F55YGO6G.cjs.map //# sourceMappingURL=chunk-F55YGO6G.cjs.map