From edb2544e608ba13ef91d1f02c50b75ca4bd1ff9c Mon Sep 17 00:00:00 2001 From: "Jyotirmoy Bandyopadhyaya [Bravo68]" Date: Thu, 20 Apr 2023 13:38:40 +0530 Subject: [PATCH] Added SSO based auth --- .gitignore | 3 ++ packages/api/auth/check.ts | 25 ++++++++++++++ packages/api/auth/middleware.ts | 32 ++++++++++++++++++ packages/api/auth/verify.ts | 10 ++++++ packages/api/configs/index.ts | 22 +++++++++++- packages/api/controllers/auth.controller.ts | 21 ++++++++++++ packages/api/hasura/metadata/actions.yaml | 8 ++--- packages/api/hasura/metadata/api_limits.yaml | 1 + .../hasura/metadata/databases/databases.yaml | 10 +++++- .../databases/default/tables/tables.yaml | 1 + .../graphql_schema_introspection.yaml | 1 + .../api/hasura/metadata/inherited_roles.yaml | 1 + packages/api/hasura/metadata/network.yaml | 1 + .../api/hasura/metadata/rest_endpoints.yaml | 1 + packages/api/helpers/auth_client.ts | 19 +++++++++++ packages/api/helpers/cache.factory.ts | 2 +- packages/api/index.ts | 27 ++++++--------- packages/api/package.json | 2 ++ packages/api/public/favicon.ico | Bin 0 -> 1150 bytes packages/api/routes/auth.routes.ts | 22 ++++++------ packages/api/routes/health.routes.ts | 16 +++++++++ packages/api/routes/index.ts | 11 +++++- packages/api/types/index.d.ts | 6 ++++ packages/api/views/pages/auth.ejs | 27 +++++++++++++++ packages/api/views/pages/index.ejs | 24 +++++++++++++ packages/api/views/partials/footer.ejs | 1 + packages/api/views/partials/head.ejs | 15 ++++++++ packages/api/views/partials/header.ejs | 8 +++++ yarn.lock | 32 ++++++++++++++++++ 29 files changed, 314 insertions(+), 35 deletions(-) create mode 100644 packages/api/auth/check.ts create mode 100644 packages/api/auth/middleware.ts create mode 100644 packages/api/auth/verify.ts create mode 100644 packages/api/controllers/auth.controller.ts create mode 100644 packages/api/hasura/metadata/api_limits.yaml create mode 100644 packages/api/hasura/metadata/databases/default/tables/tables.yaml create mode 100644 packages/api/hasura/metadata/graphql_schema_introspection.yaml create mode 100644 packages/api/hasura/metadata/inherited_roles.yaml create mode 100644 packages/api/hasura/metadata/network.yaml create mode 100644 packages/api/hasura/metadata/rest_endpoints.yaml create mode 100644 packages/api/helpers/auth_client.ts create mode 100644 packages/api/public/favicon.ico create mode 100644 packages/api/routes/health.routes.ts create mode 100644 packages/api/views/pages/auth.ejs create mode 100644 packages/api/views/pages/index.ejs create mode 100644 packages/api/views/partials/footer.ejs create mode 100644 packages/api/views/partials/head.ejs create mode 100644 packages/api/views/partials/header.ejs diff --git a/.gitignore b/.gitignore index c9281ab..8f82434 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,6 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* + +**/jwtRS256.key +**/jwtRS256.key.pub diff --git a/packages/api/auth/check.ts b/packages/api/auth/check.ts new file mode 100644 index 0000000..2ef2609 --- /dev/null +++ b/packages/api/auth/check.ts @@ -0,0 +1,25 @@ +import { authClient } from "../helpers/auth_client"; +import { generators } from 'openid-client'; +import { configKeys } from ".."; + +const code_verifier = generators.codeVerifier(); +const code_challenge = generators.codeChallenge(code_verifier); + +export default () => { + const authurl = authClient.authorizationUrl({ + scope: 'email profile openid', + code_challenge, + code_challenge_method: 'S256', + client_id: configKeys.KEYCLOAK_CLIENT_ID, + redirect_uri: configKeys.KEYCLOAK_REDIRECT_URI, + }); + + return { + authurl, + }; +} + +export { + code_challenge, + code_verifier, +} \ No newline at end of file diff --git a/packages/api/auth/middleware.ts b/packages/api/auth/middleware.ts new file mode 100644 index 0000000..720e37e --- /dev/null +++ b/packages/api/auth/middleware.ts @@ -0,0 +1,32 @@ +import { NextFunction, Response } from "express"; +import {authClient} from "../helpers/auth_client"; +import { ModRequest } from "../types"; +import { CustomError } from "../libs/error"; + +const middleware = async (req: ModRequest | any, res: Response, next: NextFunction) => { + try { + const authHeader = req.headers?.authorization?.split(' '); + if (!authHeader) { + throw new Error("No authorization header"); + } + const token : string = authHeader[1]; + const user = await authClient.userinfo(token, { + method: 'GET', + tokenType: 'Bearer', + params: { + access_token: token + }, + via: 'header' + }); + req.user = user; + next(); + } + catch (err) { + next(new CustomError({ + message: "Invalid token", + statusCode: 401 + })) + } +} + +export default middleware \ No newline at end of file diff --git a/packages/api/auth/verify.ts b/packages/api/auth/verify.ts new file mode 100644 index 0000000..8b55cb5 --- /dev/null +++ b/packages/api/auth/verify.ts @@ -0,0 +1,10 @@ +import {authClient} from "../helpers/auth_client"; +import { code_verifier } from './check' + +export default async (session_state: string, code: string) => { + return authClient.callback( + 'http://localhost:4038/auth/signin/callback', + { code_verifier, code, session_state, expires_in: "1d" }, + { code_verifier } + ); +} \ No newline at end of file diff --git a/packages/api/configs/index.ts b/packages/api/configs/index.ts index efe6943..f9f729f 100644 --- a/packages/api/configs/index.ts +++ b/packages/api/configs/index.ts @@ -1,9 +1,13 @@ import fs from 'fs' import { parse as parseFile } from 'envfile' +import { Issuer } from 'openid-client'; + +const keyCloakIssuer : Issuer = await Issuer.discover(process.env.KEYCLOAK_AUTH_SERVER_URL!); +console.log('šŸ” Connected to Keycloak'); type IconfigStore = 'development' | 'production' -interface IConfigKeys { +export interface IConfigKeys { PORT: string | number NODE_ENV: string HASURA_GRAPHQL_ADMIN_SECRET: string @@ -32,6 +36,13 @@ interface IConfigKeys { AWS_ACCESS_KEY_ID: string AWS_SECRET_ACCESS_KEY: string AWS_REGION: string + PUBLIC_KEY: string + PRIVATE_KEY: string + KEYCLOAK_ISSUER: Issuer + KEYCLOAK_CLIENT_ID: string + KEYCLOAK_CLIENT_SECRET: string + KEYCLOAK_REDIRECT_URI: string + KEYCLOAK_AUTH_SERVER_URL: string } export default class ConfigStoreFactory { @@ -46,9 +57,14 @@ export default class ConfigStoreFactory { } public async getConfigStore() { + const publicKEY = fs.readFileSync('./jwtRS256.key', 'utf8'); + const privateKEY = fs.readFileSync('./jwtRS256.key.pub', 'utf8'); if (this.configStoreType === 'development') { const envContent = await fs.readFileSync(`./.env`, 'utf8') const env: Partial = await parseFile(envContent) + env.PUBLIC_KEY = publicKEY + env.PRIVATE_KEY = privateKEY + env.KEYCLOAK_ISSUER = keyCloakIssuer return env } else { let reqEnvContent: any = await fs.readFileSync( @@ -59,6 +75,9 @@ export default class ConfigStoreFactory { reqEnvContent = reqEnvContent.split('\n') let missingKeys: string[] = [] let env: Partial = {} + env.PUBLIC_KEY = publicKEY + env.PRIVATE_KEY = privateKEY + env.KEYCLOAK_ISSUER = keyCloakIssuer for (const line of reqEnvContent) { if (!process.env[line]) { missingKeys.push(line) @@ -67,6 +86,7 @@ export default class ConfigStoreFactory { if (missingKeys.length > 0) { throw new Error(`Missing keys: ${missingKeys}`) } + return env } } diff --git a/packages/api/controllers/auth.controller.ts b/packages/api/controllers/auth.controller.ts new file mode 100644 index 0000000..ab58744 --- /dev/null +++ b/packages/api/controllers/auth.controller.ts @@ -0,0 +1,21 @@ +import { Request, Response } from 'express' +import { makeResponse } from '../libs' +import check from '../auth/check' +import verify from '../auth/verify' +import { ModRequest } from '../types' + +export default class AuthController { + public signin = (req: Request, res: Response) => { + const { authurl } = check() + res.redirect(authurl) + } + + public callback = async (req: Request, res: Response) => { + const { session_state, code } = req.query as { session_state: string, code: string} + res.send(makeResponse(await verify(session_state, code))) + } + + public me = (req: ModRequest, res: Response) => { + res.send(makeResponse(req.user)) + } +} \ No newline at end of file diff --git a/packages/api/hasura/metadata/actions.yaml b/packages/api/hasura/metadata/actions.yaml index 1979211..1edb4c2 100644 --- a/packages/api/hasura/metadata/actions.yaml +++ b/packages/api/hasura/metadata/actions.yaml @@ -1,6 +1,6 @@ actions: [] custom_types: - enums: [] - input_objects: [] - objects: [] - scalars: [] + enums: [] + input_objects: [] + objects: [] + scalars: [] diff --git a/packages/api/hasura/metadata/api_limits.yaml b/packages/api/hasura/metadata/api_limits.yaml new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/packages/api/hasura/metadata/api_limits.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/api/hasura/metadata/databases/databases.yaml b/packages/api/hasura/metadata/databases/databases.yaml index fe51488..b25fa9e 100644 --- a/packages/api/hasura/metadata/databases/databases.yaml +++ b/packages/api/hasura/metadata/databases/databases.yaml @@ -1 +1,9 @@ -[] +- name: default + kind: postgres + configuration: + connection_info: + database_url: + from_env: PG_DATABASE_URL + isolation_level: read-committed + use_prepared_statements: false + tables: "!include default/tables/tables.yaml" diff --git a/packages/api/hasura/metadata/databases/default/tables/tables.yaml b/packages/api/hasura/metadata/databases/default/tables/tables.yaml new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/packages/api/hasura/metadata/databases/default/tables/tables.yaml @@ -0,0 +1 @@ +[] diff --git a/packages/api/hasura/metadata/graphql_schema_introspection.yaml b/packages/api/hasura/metadata/graphql_schema_introspection.yaml new file mode 100644 index 0000000..61a4dca --- /dev/null +++ b/packages/api/hasura/metadata/graphql_schema_introspection.yaml @@ -0,0 +1 @@ +disabled_for_roles: [] diff --git a/packages/api/hasura/metadata/inherited_roles.yaml b/packages/api/hasura/metadata/inherited_roles.yaml new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/packages/api/hasura/metadata/inherited_roles.yaml @@ -0,0 +1 @@ +[] diff --git a/packages/api/hasura/metadata/network.yaml b/packages/api/hasura/metadata/network.yaml new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/packages/api/hasura/metadata/network.yaml @@ -0,0 +1 @@ +{} diff --git a/packages/api/hasura/metadata/rest_endpoints.yaml b/packages/api/hasura/metadata/rest_endpoints.yaml new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/packages/api/hasura/metadata/rest_endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/packages/api/helpers/auth_client.ts b/packages/api/helpers/auth_client.ts new file mode 100644 index 0000000..d7298f2 --- /dev/null +++ b/packages/api/helpers/auth_client.ts @@ -0,0 +1,19 @@ +import { configKeys } from ".."; + +const { KEYCLOAK_ISSUER } = configKeys + +const authConfig = { + client_id: configKeys.KEYCLOAK_CLIENT_ID, + 'auth-server-url': configKeys.KEYCLOAK_AUTH_SERVER_URL, + 'ssl-required': 'all', + resource: configKeys.KEYCLOAK_CLIENT_ID, + credentials: { 'secret-jwt': { secret: configKeys.KEYCLOAK_CLIENT_SECRET } }, + 'confidential-port': 0, + redirect_uri: configKeys.KEYCLOAK_REDIRECT_URI, + client_secret: configKeys.KEYCLOAK_CLIENT_SECRET, + default_max_age: 3600000, +} + +const authClient = new KEYCLOAK_ISSUER.Client(authConfig) + +export { authClient } \ No newline at end of file diff --git a/packages/api/helpers/cache.factory.ts b/packages/api/helpers/cache.factory.ts index 37ad812..2eb71a0 100644 --- a/packages/api/helpers/cache.factory.ts +++ b/packages/api/helpers/cache.factory.ts @@ -43,7 +43,7 @@ export default class CacheClient { } this._nodeClient = new NodeCache() - console.log(`Caching Client initialized in '${env}' environment`) + console.log(`šŸž Caching Client initialized in '${env}' environment`) } static async set(key: string, value: any) { diff --git a/packages/api/index.ts b/packages/api/index.ts index 4b8378f..5b46eb6 100644 --- a/packages/api/index.ts +++ b/packages/api/index.ts @@ -5,45 +5,40 @@ import morgan from 'morgan' import helmet from 'helmet' import { hgqlInit } from './helpers' +import cacheClient from './helpers/cache.factory'; import routes from './routes' import { errorHandler, notFoundHandler } from './libs' import pkg from './package.json' assert { type: 'json' } -import configStore from './configs' +import configStore, { IConfigKeys } from './configs'; export const app: express.Application = express() -hgqlInit() - console.log('šŸš€', '@b68/api', 'v' + pkg.version) +hgqlInit() +cacheClient.init(); + const isDev: boolean = process.env.NODE_ENV == 'production' -console.log(isDev ? 'šŸš€ Production Mode' : 'šŸš€ Development Mode') +console.log(isDev ? 'šŸš€ Production Mode' : 'šŸ‘· Development Mode') const configs = new configStore(isDev) -const configKeys: any = await configs.getConfigStore() +const configKeys: IConfigKeys = await configs.getConfigStore() as IConfigKeys app.use(cors()) app.use(helmet()) app.use(morgan('dev')) app.use(express.json()) app.use(express.urlencoded({ extended: true, limit: '50mb' })) +app.set('view engine', 'ejs'); -app.use('/health', (req, res) => { - return res.status(200).json({ - app: pkg.name, - request_ip: req.ip, - uptime: process.uptime(), - hrtime: process.hrtime(), - }) -}) +console.log('ā˜„ ', 'Base Route', '/') -console.log('ā˜„', 'Base Route', '/') app.use('/', routes) app.use(notFoundHandler) app.use(errorHandler) -app.listen(process.env.PORT, async () => { - console.log(`\nServer running on port ${process.env.PORT}`) +app.listen(configKeys.PORT, async () => { + console.log(`\nšŸŒˆ Server running on port ${configKeys.PORT}`) }) export { configKeys } diff --git a/packages/api/package.json b/packages/api/package.json index dd2a9a7..ce7c6ae 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -14,6 +14,7 @@ "axios": "^1.2.1", "cors": "^2.8.5", "dotenv": "^16.0.3", + "ejs": "^3.1.9", "envfile": "^6.18.0", "express": "^4.18.2", "form-data": "^4.0.0", @@ -27,6 +28,7 @@ "napi-nanoid": "^0.0.4", "node-cache": "^5.1.2", "nodemailer": "^6.8.0", + "openid-client": "^5.4.0", "osu-api-extended": "^2.5.12", "redis": "^4.5.1", "typescript": "^4.9.3" diff --git a/packages/api/public/favicon.ico b/packages/api/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3f464f351776124181a3def45f9bb44bde7ad3d3 GIT binary patch literal 1150 zcmb7^Sx*yD7>3706C+?p+D;dsw9|H4yV62iK*XXLDLV)ykhq}6s8L)}6{8>;7lKG2 z5n>cIih84odgBi;Tp2I@BmRQNGsR+6Zk)+G=R4nd-*21ANYW;8%d#Y%PU+NUNm3+9 z@(T!;@T~d8B1z)x@5`we*a+3;?fk~ZoMN5Mb(qSiGL{nYI2i8lWTY>{aBqhGj{Stx z3LN50=jbTbIu)5z#LupHh=y2z=46z74>LO^B%6bg9 zt(-eI$9ewr5s&6)c((MACkyv@H8;VF2jeU+%`$oA9B)^aSzMUm@#0)QPoWN%MJB#e zr7q;9xkh6!T|*|O^5KNa$BRzd6K;AM1Ek}Al3^bS!SmRS>-qIw9HM`Z#X!<+p+%Fq z+qIn=Z3ZU0gxw?45U`PQD|oDe`%nJ{ytW-AR15u41FOeNm}-~l(n{zHZsT%?mCpJ5 zIJ&w?s!E<)JiltQ$m_AN%U8jrbQ#~rO6Uw3d3~&&Z?lbzw%Q54`-C#RL{p82l;G-` zLJWUJIcZVf>3RcG83S)e4RrVPFtqZ8!=G0f9vh_U>^R=3X<~a*H2bXV6dGM$Ef98? zL~ez}Lo)A=mU3o~2`xLuQ0^K>X08#weVgdMz076JTy4_layZ{^4NExfsEWuU>tY_Ev}0fms@7HZd5Rm?r^vT(h%nw3!}2jezQ)*H!1 zOZa-Ol&e{Vj;NiNN1aRvPF&1c*A#MxD$A*>3o|g4W1vN&)@f$9W@W$E#7N9Uqt{AU zED?Uk2> literal 0 HcmV?d00001 diff --git a/packages/api/routes/auth.routes.ts b/packages/api/routes/auth.routes.ts index d82a717..f90476d 100644 --- a/packages/api/routes/auth.routes.ts +++ b/packages/api/routes/auth.routes.ts @@ -1,18 +1,18 @@ import { Router } from 'express' -import { makeResponse } from '../libs' +import AuthController from '../controllers/auth.controller' +import middleware from '../auth/middleware' const router = Router() +const authController = new AuthController() -router.get('/', (req, res) => { - res.send(makeResponse({ message: 'Hello World auth!' })) -}) +router.get('/signin', authController.signin) -router.all('/err', async (req, res, next) => { - try { - throw new Error('This is an error') - } catch (err) { - next(err) - } -}) +router.get('/signin/callback', authController.callback) + +router.get('/me', middleware, authController.me as any) + +router.get('/', function(req, res) { + res.render('pages/auth'); +}); export default router diff --git a/packages/api/routes/health.routes.ts b/packages/api/routes/health.routes.ts new file mode 100644 index 0000000..a4147a0 --- /dev/null +++ b/packages/api/routes/health.routes.ts @@ -0,0 +1,16 @@ +import { Router } from 'express' + +const router = Router() + +router.use('/health', + (req, res) => { + return res.status(200).json({ + status: "OK", + app: "B68 API", + request_ip: req.ip, + uptime: process.uptime(), + hrtime: process.hrtime(), + }) +}) + +export default router diff --git a/packages/api/routes/index.ts b/packages/api/routes/index.ts index be7fecd..1adeb73 100644 --- a/packages/api/routes/index.ts +++ b/packages/api/routes/index.ts @@ -30,7 +30,7 @@ const loadRoutes = async (dirPath: string, prefix = '/') => { '' ) const modRoute = path.join(prefix, route) - console.log('šŸ›°ļø', 'Loaded', modRoute) + console.log('šŸ›°ļø ', 'Loaded', modRoute) const mod = await import(path.join(baseDir, prefix + f.name)) router.use(modRoute, mod.default) @@ -48,4 +48,13 @@ let baseDir = path.dirname(__filename) baseDir = path.resolve(baseDir) loadRoutes(baseDir) + +router.get('/', function(req, res) { + res.render('pages/index'); +}); + +router.get('/favicon.ico', function(req, res) { + res.sendFile(path.join(__dirname, '../public', 'favicon.ico')); +}); + export default router diff --git a/packages/api/types/index.d.ts b/packages/api/types/index.d.ts index 73af2e7..b47ae84 100644 --- a/packages/api/types/index.d.ts +++ b/packages/api/types/index.d.ts @@ -1,3 +1,5 @@ +import { Request } from 'express' + export interface PaginationType { page: number limit: number @@ -5,3 +7,7 @@ export interface PaginationType { sort_by?: string filters?: { [k: string]: any } } + +export interface ModRequest extends Request { + user: any +} \ No newline at end of file diff --git a/packages/api/views/pages/auth.ejs b/packages/api/views/pages/auth.ejs new file mode 100644 index 0000000..672ed67 --- /dev/null +++ b/packages/api/views/pages/auth.ejs @@ -0,0 +1,27 @@ + + + + <%- include('../partials/head'); %> + + + +
+ <%- include('../partials/header'); %> +
+ +
+ +
+ +
+ <%- include('../partials/footer'); %> +
+ + + \ No newline at end of file diff --git a/packages/api/views/pages/index.ejs b/packages/api/views/pages/index.ejs new file mode 100644 index 0000000..3a7d7c4 --- /dev/null +++ b/packages/api/views/pages/index.ejs @@ -0,0 +1,24 @@ + + + + <%- include('../partials/head'); %> + + + +
+ <%- include('../partials/header'); %> +
+ +
+
+

API Landing

+

Welcome to B68 API Home

+
+
+ +
+ <%- include('../partials/footer'); %> +
+ + + \ No newline at end of file diff --git a/packages/api/views/partials/footer.ejs b/packages/api/views/partials/footer.ejs new file mode 100644 index 0000000..55de3d0 --- /dev/null +++ b/packages/api/views/partials/footer.ejs @@ -0,0 +1 @@ +

© Copyright 2023 Jyotirmoy Bandyopadhayaya | Github

\ No newline at end of file diff --git a/packages/api/views/partials/head.ejs b/packages/api/views/partials/head.ejs new file mode 100644 index 0000000..6929440 --- /dev/null +++ b/packages/api/views/partials/head.ejs @@ -0,0 +1,15 @@ + +B68 API + + + + + \ No newline at end of file diff --git a/packages/api/views/partials/header.ejs b/packages/api/views/partials/header.ejs new file mode 100644 index 0000000..cff0e8d --- /dev/null +++ b/packages/api/views/partials/header.ejs @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3993607..c357360 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3754,6 +3754,13 @@ ejs@^3.1.7: dependencies: jake "^10.8.5" +ejs@^3.1.9: + version "3.1.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" + integrity sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ== + dependencies: + jake "^10.8.5" + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" @@ -5332,6 +5339,11 @@ joi@^17.7.0: "@sideway/formula" "^3.0.0" "@sideway/pinpoint" "^2.0.0" +jose@^4.10.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.14.0.tgz#c8c03579a0ba3598194c92ccca777d96adca8f48" + integrity sha512-LSA/XenLPwqk6e2L+PSUNuuY9G4NGsvjRWz6sJcUBmzTLEPJqQh46FHSUxnAQ64AWOkRO6bSXpy3yXuEKZkbIA== + js-sdsl@^4.1.4: version "4.2.0" resolved "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz" @@ -6464,6 +6476,11 @@ object-assign@^4, object-assign@^4.1.1: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-hash@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" @@ -6519,6 +6536,11 @@ object.values@^1.1.5, object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" +oidc-token-hash@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.2.tgz#f9ca7f7f1f92d721a2973e66b7430cb52a486648" + integrity sha512-U91Ba78GtVBxcExLI7U+hC2AwJQqXQEW/D3fjmJC4hhSVIgdl954KO4Gu95WqAlgDKJdLATxkmuxraWLT0fVRQ== + on-finished@2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" @@ -6568,6 +6590,16 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" +openid-client@^5.4.0: + version "5.4.0" + resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.4.0.tgz#77f1cda14e2911446f16ea3f455fc7c405103eac" + integrity sha512-hgJa2aQKcM2hn3eyVtN12tEA45ECjTJPXCgUh5YzTzy9qwapCvmDTVPWOcWVL0d34zeQoQ/hbG9lJhl3AYxJlQ== + dependencies: + jose "^4.10.0" + lru-cache "^6.0.0" + object-hash "^2.0.1" + oidc-token-hash "^5.0.1" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz"