UNPKG

oauth-entra-id

Version:

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

1 lines 16.5 kB
{"version":3,"sources":["../src/shared/endpoints.ts","../src/shared/middleware.ts"],"names":["OAuthError","setCookie","deleteCookie","$err","accessTokenName","refreshTokenName","$ok","getCookie"],"mappings":";;;;;AAUA,eAAsB,2BAAA,CAA4B,KAAc,GAAA,EAAe;AAC7E,EAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,EAAA,MAAM,SAAS,IAAA,GACX,EAAE,WAAA,EAAa,IAAA,CAAK,aAAa,KAAA,EAAO,IAAA,CAAK,KAAA,EAAO,WAAA,EAAa,KAAK,WAAA,EAAa,OAAA,EAAS,IAAA,CAAK,OAAA,KACjG,EAAC;AAEL,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,GAAA,CAAI,aAAA,CAAc,WAAW,MAAM,CAAA;AAE7D,EAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,GAAA,EAAK,SAAS,CAAA;AACvC;AAOA,eAAsB,qBAAA,CAAsB,KAAc,GAAA,EAAe;AACvE,EAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,EAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAIA,4BAAA,CAAW,EAAE,GAAA,EAAK,gBAAA,EAAkB,IAAA,EAAM,kCAAA,EAAoC,CAAA;AAEnG,EAAA,MAAM,EAAE,aAAa,YAAA,EAAc,WAAA,KAAgB,MAAM,GAAA,CAAI,cAAc,cAAA,CAAe;AAAA,IACxF,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,OAAO,IAAA,CAAK;AAAA,GACb,CAAA;AAED,EAAAC,uBAAA,CAAU,KAAK,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,KAAA,EAAO,YAAY,OAAO,CAAA;AACvE,EAAA,IAAI,YAAA,0BAAwB,GAAA,EAAK,YAAA,CAAa,MAAM,YAAA,CAAa,KAAA,EAAO,aAAa,OAAO,CAAA;AAC5F,EAAA,GAAA,CAAI,QAAA,CAAS,KAAK,WAAW,CAAA;AAC/B;AAOA,eAAsB,mBAAA,CAAoB,KAAc,GAAA,EAAe;AACrE,EAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,EAAA,MAAM,MAAA,GAAS,IAAA,GAAO,EAAE,WAAA,EAAa,IAAA,CAAK,aAAa,OAAA,EAAS,IAAA,CAAK,OAAA,EAAQ,GAAI,EAAC;AAElF,EAAA,MAAM,EAAE,WAAW,iBAAA,EAAmB,kBAAA,KAAuB,MAAM,GAAA,CAAI,aAAA,CAAc,YAAA,CAAa,MAAM,CAAA;AAExG,EAAAC,0BAAA,CAAa,GAAA,EAAK,kBAAA,CAAmB,IAAA,EAAM,kBAAA,CAAmB,OAAO,CAAA;AACrE,EAAAA,0BAAA,CAAa,GAAA,EAAK,iBAAA,CAAkB,IAAA,EAAM,iBAAA,CAAkB,OAAO,CAAA;AACnE,EAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,GAAA,EAAK,WAAW,CAAA;AACzC;AAQA,eAAsB,uBAAA,CAAwB,KAAc,GAAA,EAAe;AACzE,EAAA,MAAM,OAAO,GAAA,CAAI,IAAA;AACjB,EAAA,IAAI,CAAC,IAAA,EAAM,MAAM,IAAIF,4BAAA,CAAW,EAAE,GAAA,EAAK,gBAAA,EAAkB,IAAA,EAAM,gCAAA,EAAkC,CAAA;AAEjG,EAAA,IAAI,CAAC,GAAA,CAAI,eAAA,EAAiB,GAAA,EAAK;AAC7B,IAAA,MAAM,IAAIA,4BAAA,CAAW;AAAA,MACnB,GAAA,EAAK,cAAA;AAAA,MACL,IAAA,EAAM,oDAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAEA,EAAA,IAAI,GAAA,CAAI,QAAA,EAAU,KAAA,KAAU,IAAA,EAAM;AAChC,IAAA,MAAM,IAAIA,4BAAA,CAAW;AAAA,MACnB,GAAA,EAAK,WAAA;AAAA,MACL,IAAA,EAAM,qDAAA;AAAA,MACN,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,MAAM,GAAA,CAAI,cAAc,kBAAA,CAAmB;AAAA,IAC7D,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,WAAA,EAAa,IAAI,eAAA,CAAgB,GAAA;AAAA,IACjC,SAAS,IAAA,CAAK;AAAA,GACf,CAAA;AAED,EAAA,KAAA,MAAW,EAAE,WAAA,EAAY,IAAK,OAAA,EAAS;AACrC,IAAAC,uBAAA,CAAU,KAAK,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,KAAA,EAAO,YAAY,OAAO,CAAA;AAAA,EACzE;AAEA,EAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,IAAA,CAAK,EAAE,SAAA,EAAW,OAAA,CAAQ,QAAQ,CAAA;AACpD;AClFA,eAAsB,iBAAA,CACpB,KACA,GAAA,EACoE;AACpE,EAAA,MAAM,GAAA,GAAM,MAAM,cAAA,CAAe,GAAG,CAAA;AACpC,EAAA,IAAI,IAAI,KAAA,EAAO,MAAM,IAAID,4BAAA,CAAW,IAAI,KAAK,CAAA;AAC7C,EAAA,IAAI,IAAI,QAAA,EAAU;AAChB,IAAA,OAAO;AAAA,MACL,UAAU,GAAA,CAAI,QAAA;AAAA,MACd,aAAA,EAAe,CAAC,KAAA,KACd,OAAA,CAAQ,OAAA;AAAA,QACNG,uBAAK,EAAE,GAAA,EAAK,mBAAA,EAAqB,IAAA,EAAM,4DAA4D;AAAA;AACrG,KACJ;AAAA,EACF;AAEA,EAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,GAAA,EAAK,GAAG,CAAA;AAC7C,EAAA,MAAM,EAAE,OAAA,EAAQ,GAAI,GAAA,CAAI,aAAA,CAAc,QAAA;AAEtC,EAAA,IAAI,UAAA,GAA+B,IAAA;AACnC,EAAA,KAAA,MAAW,EAAE,eAAA,EAAiB,gBAAA,EAAiB,IAAK,QAAQ,WAAA,EAAa;AACvE,IAAA,MAAM,SAAS,MAAM,kBAAA,CAAmB,KAAK,GAAA,EAAK,UAAA,EAAY,iBAAiB,gBAAgB,CAAA;AAC/F,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,IAAI,CAAC,UAAA,EAAY,UAAA,GAAa,MAAA,CAAO,KAAA;AACrC,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,EAAE,SAAS,eAAA,EAAAC,gBAAAA,EAAiB,kBAAAC,iBAAAA,EAAiB,IAAK,QAAQ,WAAA,EAAa;AAChF,MAAA,IAAI,OAAA,KAAY,MAAA,CAAO,QAAA,CAAS,OAAA,EAAS;AACzC,MAAAH,0BAAAA,CAAa,GAAA,EAAKE,gBAAAA,EAAiB,OAAA,CAAQ,aAAa,CAAA;AACxD,MAAAF,0BAAAA,CAAa,GAAA,EAAKG,iBAAAA,EAAkB,OAAA,CAAQ,aAAa,CAAA;AAAA,IAC3D;AAEA,IAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,EAAU,aAAA,EAAe,OAAO,aAAA,EAAc;AAAA,EAC1E;AAEA,EAAA,MAAM,IAAIL,4BAAA,CAAW,UAAA,IAAcG,sBAAA,CAAK,EAAE,GAAA,EAAK,cAAA,EAAgB,IAAA,EAAM,+BAAA,EAAiC,MAAA,EAAQ,GAAA,EAAK,CAAC,CAAA;AACtH;AAEA,SAAS,iBAAA,CAAkB,KAAc,GAAA,EAAe;AACtD,EAAA,OAAO,OACL,aACA,IAAA,KACyC;AACzC,IAAA,MAAM,GAAA,GAAM,MAAM,GAAA,CAAI,aAAA,CAAc,cAAc,EAAE,WAAA,EAAa,MAAM,CAAA;AACvE,IAAA,IAAI,GAAA,CAAI,KAAA,EAAO,OAAOA,sBAAA,CAAK,IAAI,KAAK,CAAA;AACpC,IAAA,IAAI,GAAA,CAAI,QAAA,EAAU,KAAA,KAAU,KAAA,EAAO;AACjC,MAAA,OAAOA,uBAAK,EAAE,GAAA,EAAK,mBAAA,EAAqB,IAAA,EAAM,4DAA4D,CAAA;AAAA,IAC5G;AACA,IAAAF,uBAAAA,CAAU,GAAA,EAAK,GAAA,CAAI,cAAA,CAAe,IAAA,EAAM,IAAI,cAAA,CAAe,KAAA,EAAO,GAAA,CAAI,cAAA,CAAe,OAAO,CAAA;AAC5F,IAAA,GAAA,CAAI,WAAW,EAAE,GAAG,GAAA,CAAI,QAAA,EAAU,cAAc,IAAA,EAAK;AACrD,IAAA,OAAOK,qBAAA,CAAI,EAAE,YAAA,EAAc,IAAA,EAAM,CAAA;AAAA,EACnC,CAAA;AACF;AAEA,eAAe,eAAe,GAAA,EAAmE;AAC/F,EAAA,MAAM,UAAA,GAAa,IAAI,OAAA,CAAQ,aAAA;AAC/B,EAAA,IAAI,CAAC,GAAA,CAAI,aAAA,CAAc,QAAA,CAAS,iBAAA,IAAqB,CAAC,UAAA,EAAY,OAAOA,qBAAA,CAAI,EAAE,QAAA,EAAU,MAAA,EAAW,CAAA;AAEpG,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,UAAA,CAAW,SAAS,CAAA,GAAI,WAAW,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA;AAC5E,EAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,aAAA,CAAc,kBAAkB,KAAK,CAAA;AAC9D,EAAA,IAAI,MAAA,CAAO,KAAA,EAAO,OAAOH,sBAAA,CAAK,OAAO,KAAK,CAAA;AAC1C,EAAA,OAAOG,qBAAA,CAAI,EAAE,QAAA,EAAU,SAAA,CAAU,GAAA,EAAK,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,MAAA,EAAQ,MAAA,CAAO,OAAO,CAAA,EAAG,CAAA;AACrF;AAEA,eAAe,kBAAA,CACb,GAAA,EACA,GAAA,EACA,UAAA,EACA,iBACA,gBAAA,EAC6F;AAC7F,EAAA,MAAM,WAAA,GAAcC,uBAAA,CAAU,GAAA,EAAK,eAAe,CAAA;AAClD,EAAA,MAAM,YAAA,GAAeA,uBAAA,CAAU,GAAA,EAAK,gBAAgB,CAAA;AACpD,EAAA,IAAI,CAAC,WAAA,IAAe,CAAC,YAAA,EAAc;AACjC,IAAA,OAAOJ,sBAAA,CAAK,EAAE,GAAA,EAAK,cAAA,EAAgB,MAAM,iDAAA,EAAmD,MAAA,EAAQ,KAAK,CAAA;AAAA,EAC3G;AAEA,EAAA,MAAM,EAAA,GAAK,MAAM,GAAA,CAAI,aAAA,CAAc,kBAAkB,WAAW,CAAA;AAChE,EAAA,IAAI,GAAG,KAAA,IAAS,CAAC,cAAc,OAAOA,sBAAA,CAAK,GAAG,KAAK,CAAA;AACnD,EAAA,IAAI,GAAG,OAAA,EAAS;AACd,IAAA,OAAOG,qBAAA,CAAI;AAAA,MACT,OAAA,EAAS,GAAG,IAAA,CAAK,OAAA;AAAA,MACjB,QAAA,EAAU,SAAA,CAAU,GAAA,EAAK,EAAA,CAAG,IAAA,EAAM,GAAG,MAAA,EAAQ,EAAA,CAAG,OAAA,EAAS,EAAA,CAAG,YAAY,CAAA;AAAA,MACxE,eAAe,CAAC,IAAA,KAA8B,UAAA,CAAW,EAAA,CAAG,QAAQ,IAAI;AAAA,KACzE,CAAA;AAAA,EACH;AAEA,EAAA,MAAM,EAAA,GAAK,MAAM,GAAA,CAAI,aAAA,CAAc,iBAAiB,YAAY,CAAA;AAChE,EAAA,IAAI,EAAA,CAAG,KAAA,EAAO,OAAOH,sBAAA,CAAK,GAAG,KAAK,CAAA;AAElC,EAAAF,uBAAAA,CAAU,GAAA,EAAK,EAAA,CAAG,cAAA,CAAe,IAAA,EAAM,GAAG,cAAA,CAAe,KAAA,EAAO,EAAA,CAAG,cAAA,CAAe,OAAO,CAAA;AACzF,EAAA,IAAI,EAAA,CAAG,eAAA,EAAiBA,uBAAAA,CAAU,GAAA,EAAK,EAAA,CAAG,eAAA,CAAgB,IAAA,EAAM,EAAA,CAAG,eAAA,CAAgB,KAAA,EAAO,EAAA,CAAG,gBAAgB,OAAO,CAAA;AAEpH,EAAA,OAAOK,qBAAA,CAAI;AAAA,IACT,OAAA,EAAS,GAAG,IAAA,CAAK,OAAA;AAAA,IACjB,QAAA,EAAU,UAAU,GAAA,EAAK,EAAA,CAAG,MAAM,EAAA,CAAG,MAAA,EAAQ,GAAG,OAAO,CAAA;AAAA,IACvD,eAAe,CAAC,IAAA,KAA8B,UAAA,CAAW,EAAA,CAAG,QAAQ,IAAI;AAAA,GACzE,CAAA;AACH;AAEA,SAAS,SAAA,CACP,GAAA,EACA,IAAA,EACA,MAAA,EACA,SACA,YAAA,EACU;AACV,EAAA,MAAM,QAAA,GAAqB;AAAA,IACzB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,UAAU,IAAA,CAAK,QAAA;AAAA,IACf,OAAO,IAAA,CAAK,KAAA;AAAA,IACZ,GAAI,IAAA,CAAK,KAAA,GACL,EAAE,KAAA,EAAO,IAAA,EAAe,OAAO,IAAA,CAAK,KAAA,KACpC,EAAE,KAAA,EAAO,OAAgB,IAAA,EAAM,IAAA,CAAK,MAAgB,KAAA,EAAO,IAAA,CAAK,OAAiB,YAAA;AAAa,GACpG;AAEA,EAAA,GAAA,CAAI,QAAA,GAAW,QAAA;AACf,EAAA,GAAA,CAAI,eAAA,GAAkB,EAAE,GAAA,EAAK,MAAA,EAAQ,SAAkB,IAAA,EAAW;AAElE,EAAA,OAAO,QAAA;AACT","file":"chunk-F55YGO6G.cjs","sourcesContent":["import type { Request, Response } from 'express';\r\nimport { deleteCookie, setCookie } from 'modern-cookies';\r\nimport { OAuthError } from '~/error';\r\nimport type { Endpoints } from './types';\r\n\r\n/**\r\n * Initiates the OAuth login flow by returning an authorization URL.\r\n *\r\n * @throws {OAuthError} if sessionType ≠ 'cookie-session' or MSAL errors occur\r\n */\r\nexport async function $sharedHandleAuthentication(req: Request, res: Response) {\r\n const body = req.body as Endpoints['Authenticate'] | undefined;\r\n const params = body\r\n ? { loginPrompt: body.loginPrompt, email: body.email, frontendUrl: body.frontendUrl, azureId: body.azureId }\r\n : {};\r\n\r\n const { authUrl } = await req.oauthProvider.getAuthUrl(params);\r\n\r\n res.status(200).json({ url: authUrl });\r\n}\r\n\r\n/**\r\n * Initiates the OAuth login flow by returning an authorization URL.\r\n *\r\n * @throws {OAuthError} if sessionType ≠ 'cookie-session' or MSAL errors occur\r\n */\r\nexport async function $sharedHandleCallback(req: Request, res: Response) {\r\n const body = req.body as Endpoints['Callback'] | undefined;\r\n if (!body) throw new OAuthError({ msg: 'Invalid params', desc: 'Body must contain code and state' });\r\n\r\n const { accessToken, refreshToken, frontendUrl } = await req.oauthProvider.getTokenByCode({\r\n code: body.code,\r\n state: body.state,\r\n });\r\n\r\n setCookie(res, accessToken.name, accessToken.value, accessToken.options);\r\n if (refreshToken) setCookie(res, refreshToken.name, refreshToken.value, refreshToken.options);\r\n res.redirect(303, frontendUrl);\r\n}\r\n\r\n/**\r\n * Clears session cookies and returns the Azure logout URL.\r\n *\r\n * @throws {OAuthError} on misconfiguration or invalid params\r\n */\r\nexport async function $sharedHandleLogout(req: Request, res: Response) {\r\n const body = req.body as Endpoints['Logout'] | undefined;\r\n const params = body ? { frontendUrl: body.frontendUrl, azureId: body.azureId } : {};\r\n\r\n const { logoutUrl, deleteAccessToken, deleteRefreshToken } = await req.oauthProvider.getLogoutUrl(params);\r\n\r\n deleteCookie(res, deleteRefreshToken.name, deleteRefreshToken.options);\r\n deleteCookie(res, deleteAccessToken.name, deleteAccessToken.options);\r\n res.status(200).json({ url: logoutUrl });\r\n}\r\n\r\n/**\r\n * Executes the On-Behalf-Of flow: acquires downstream tokens,\r\n * sets service cookies, and returns the count of tokens set.\r\n *\r\n * @throws {OAuthError} on misconfiguration, missing access token, or forbidden app contexts\r\n */\r\nexport async function $sharedHandleOnBehalfOf(req: Request, res: Response) {\r\n const body = req.body as Endpoints['OnBehalfOf'] | undefined;\r\n if (!body) throw new OAuthError({ msg: 'Invalid params', desc: 'Body must contain serviceNames' });\r\n\r\n if (!req.accessTokenInfo?.jwt) {\r\n throw new OAuthError({\r\n msg: 'Unauthorized',\r\n desc: 'Access token is required for on-behalf-of requests',\r\n status: 401,\r\n });\r\n }\r\n\r\n if (req.userInfo?.isApp === true) {\r\n throw new OAuthError({\r\n msg: 'Forbidden',\r\n desc: 'On-behalf-of requests are not allowed for app users',\r\n status: 403,\r\n });\r\n }\r\n\r\n const { results } = await req.oauthProvider.getTokenOnBehalfOf({\r\n services: body.services,\r\n accessToken: req.accessTokenInfo.jwt,\r\n azureId: body.azureId,\r\n });\r\n\r\n for (const { accessToken } of results) {\r\n setCookie(res, accessToken.name, accessToken.value, accessToken.options);\r\n }\r\n\r\n res.status(200).json({ tokensSet: results.length });\r\n}\r\n","import type { Request, Response } from 'express';\r\nimport { deleteCookie, getCookie, setCookie } from 'modern-cookies';\r\nimport { $err, $ok, OAuthError, type Result, type ResultErr } from '~/error';\r\nimport type { JwtPayload, Metadata } from '~/types';\r\nimport type { InjectDataFunction, UserInfo } from './types';\r\n\r\n/**\r\n * Validates or refreshes a session cookie, attaches `userInfo`, and returns an InjectDataFunction for adding metadata to the access token.\r\n *\r\n * @throws {OAuthError} on misconfiguration, missing tokens, or verification failure\r\n */\r\nexport async function $sharedMiddleware(\r\n req: Request,\r\n res: Response,\r\n): Promise<{ userInfo: UserInfo; tryInjectData: InjectDataFunction }> {\r\n const b2b = await $checkB2BToken(req);\r\n if (b2b.error) throw new OAuthError(b2b.error);\r\n if (b2b.userInfo) {\r\n return {\r\n userInfo: b2b.userInfo,\r\n tryInjectData: (_data) =>\r\n Promise.resolve(\r\n $err({ msg: 'Invalid user type', desc: 'Injecting data is only supported for user-based sessions' }),\r\n ),\r\n };\r\n }\r\n\r\n const injectFunc = $createInjectFunc(req, res);\r\n const { cookies } = req.oauthProvider.settings;\r\n\r\n let firstError: ResultErr | null = null;\r\n for (const { accessTokenName, refreshTokenName } of cookies.cookieNames) {\r\n const cookie = await $checkCookieTokens(req, res, injectFunc, accessTokenName, refreshTokenName);\r\n if (cookie.error) {\r\n if (!firstError) firstError = cookie.error;\r\n continue;\r\n }\r\n\r\n for (const { azureId, accessTokenName, refreshTokenName } of cookies.cookieNames) {\r\n if (azureId === cookie.userInfo.azureId) continue;\r\n deleteCookie(res, accessTokenName, cookies.deleteOptions);\r\n deleteCookie(res, refreshTokenName, cookies.deleteOptions);\r\n }\r\n\r\n return { userInfo: cookie.userInfo, tryInjectData: cookie.tryInjectData };\r\n }\r\n\r\n throw new OAuthError(firstError ?? $err({ msg: 'Unauthorized', desc: 'Tokens are invalid or missing', status: 401 }));\r\n}\r\n\r\nfunction $createInjectFunc(req: Request, res: Response) {\r\n return async <T extends object = Record<string, any>>(\r\n accessToken: string,\r\n data: T,\r\n ): Promise<Result<{ injectedData: T }>> => {\r\n const inj = await req.oauthProvider.tryInjectData({ accessToken, data });\r\n if (inj.error) return $err(inj.error);\r\n if (req.userInfo?.isApp !== false) {\r\n return $err({ msg: 'Invalid user type', desc: 'Injecting data is only supported for user-based sessions' });\r\n }\r\n setCookie(res, inj.newAccessToken.name, inj.newAccessToken.value, inj.newAccessToken.options);\r\n req.userInfo = { ...req.userInfo, injectedData: data };\r\n return $ok({ injectedData: data });\r\n };\r\n}\r\n\r\nasync function $checkB2BToken(req: Request): Promise<Result<{ userInfo: UserInfo | undefined }>> {\r\n const authHeader = req.headers.authorization;\r\n if (!req.oauthProvider.settings.acceptB2BRequests || !authHeader) return $ok({ userInfo: undefined });\r\n\r\n const token = authHeader.startsWith('Bearer ') ? authHeader.split(' ')[1] : undefined;\r\n const bearer = await req.oauthProvider.verifyAccessToken(token);\r\n if (bearer.error) return $err(bearer.error);\r\n return $ok({ userInfo: $userInfo(req, bearer.meta, bearer.rawJwt, bearer.payload) });\r\n}\r\n\r\nasync function $checkCookieTokens(\r\n req: Request,\r\n res: Response,\r\n injectFunc: ReturnType<typeof $createInjectFunc>,\r\n accessTokenName: string,\r\n refreshTokenName: string,\r\n): Promise<Result<{ azureId: string; userInfo: UserInfo; tryInjectData: InjectDataFunction }>> {\r\n const accessToken = getCookie(req, accessTokenName);\r\n const refreshToken = getCookie(req, refreshTokenName);\r\n if (!accessToken && !refreshToken) {\r\n return $err({ msg: 'Unauthorized', desc: 'Access token and refresh token are both missing', status: 401 });\r\n }\r\n\r\n const at = await req.oauthProvider.verifyAccessToken(accessToken);\r\n if (at.error && !refreshToken) return $err(at.error);\r\n if (at.success) {\r\n return $ok({\r\n azureId: at.meta.azureId as string,\r\n userInfo: $userInfo(req, at.meta, at.rawJwt, at.payload, at.injectedData),\r\n tryInjectData: (data: Record<string, any>) => injectFunc(at.rawJwt, data),\r\n });\r\n }\r\n\r\n const rt = await req.oauthProvider.tryRefreshTokens(refreshToken);\r\n if (rt.error) return $err(rt.error);\r\n\r\n setCookie(res, rt.newAccessToken.name, rt.newAccessToken.value, rt.newAccessToken.options);\r\n if (rt.newRefreshToken) setCookie(res, rt.newRefreshToken.name, rt.newRefreshToken.value, rt.newRefreshToken.options);\r\n\r\n return $ok({\r\n azureId: rt.meta.azureId as string,\r\n userInfo: $userInfo(req, rt.meta, rt.rawJwt, rt.payload),\r\n tryInjectData: (data: Record<string, any>) => injectFunc(rt.rawJwt, data),\r\n });\r\n}\r\n\r\nfunction $userInfo<T extends object = Record<string, any>>(\r\n req: Request,\r\n meta: Metadata,\r\n rawJwt: string,\r\n payload: JwtPayload,\r\n injectedData?: T,\r\n): UserInfo {\r\n const userInfo: UserInfo = {\r\n azureId: meta.azureId as string,\r\n tenantId: meta.tenantId as string,\r\n uniqueId: meta.uniqueId as string,\r\n roles: meta.roles as string[],\r\n ...(meta.isApp\r\n ? { isApp: true as const, appId: meta.appId as string }\r\n : { isApp: false as const, name: meta.name as string, email: meta.email as string, injectedData }),\r\n } as const;\r\n\r\n req.userInfo = userInfo;\r\n req.accessTokenInfo = { jwt: rawJwt, payload: payload, meta: meta };\r\n\r\n return userInfo;\r\n}\r\n"]}