diff --git a/api/.env.development b/api/.env.development
deleted file mode 100644
index 35c73302..00000000
--- a/api/.env.development
+++ /dev/null
@@ -1 +0,0 @@
-JWT_SECRET=thisisasecretthatshouldntbeusedinprod
diff --git a/api/package.json b/api/package.json
index c8990697..11c1faab 100644
--- a/api/package.json
+++ b/api/package.json
@@ -23,12 +23,17 @@
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.0.0",
"@nestjs/jwt": "^10.2.0",
+ "@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/typeorm": "^10.0.1",
+ "@types/passport-jwt": "^3.0.13",
"bcrypt": "^5.1.1",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"generate-password": "^1.7.1",
+ "jwks-rsa": "^3.1.0",
+ "passport": "^0.7.0",
+ "passport-jwt": "^4.0.1",
"postgres": "^3.4.3",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
diff --git a/api/src/app.module.ts b/api/src/app.module.ts
index 1d0aac4f..65f145b4 100644
--- a/api/src/app.module.ts
+++ b/api/src/app.module.ts
@@ -8,7 +8,7 @@ import { UsersModule } from './users/users.module';
// 3rd Party Modules
const LIBRARY_IMPORTS = [
- ConfigModule.forRoot({ cache: true, isGlobal: true, envFilePath: [".env.development", ".env"] }),
+ ConfigModule.forRoot({ cache: true, isGlobal: true, envFilePath: [".env", ".env.development"] }),
TypeOrmModule.forRoot(getDatabaseConfig()),
];
@@ -24,6 +24,8 @@ const FEATURE_IMPORTS = [
...FEATURE_IMPORTS,
],
controllers: [AppController],
- providers: [AppService],
+ providers: [
+ AppService
+ ],
})
export class AppModule {}
diff --git a/api/src/users/jwt.strategy.ts b/api/src/users/jwt.strategy.ts
new file mode 100644
index 00000000..5332cd68
--- /dev/null
+++ b/api/src/users/jwt.strategy.ts
@@ -0,0 +1,28 @@
+import { Injectable } from '@nestjs/common';
+import { ConfigService } from '@nestjs/config';
+import { PassportStrategy } from '@nestjs/passport';
+import { passportJwtSecret } from 'jwks-rsa';
+import { ExtractJwt, Strategy } from 'passport-jwt';
+
+@Injectable()
+export class JwtStrategy extends PassportStrategy(Strategy) {
+ constructor(private configService: ConfigService) {
+ super({
+ secretOrKeyProvider: passportJwtSecret({
+ cache: true,
+ rateLimit: true,
+ jwksRequestsPerMinute: 5,
+ jwksUri: 'https://id.realliance.net/application/o/profile/jwks/',
+ }),
+
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
+ audience: 'LNXdUuOZUue5HPlw8Vyglo83sIYndFaGUCIdQrSZ',
+ issuer: 'https://id.realliance.net/application/o/profile/',
+ algorithms: ['RS256'],
+ });
+ }
+
+ validate(payload: unknown): unknown {
+ return payload;
+ }
+}
\ No newline at end of file
diff --git a/api/src/users/user.controller.ts b/api/src/users/user.controller.ts
new file mode 100644
index 00000000..d183e805
--- /dev/null
+++ b/api/src/users/user.controller.ts
@@ -0,0 +1,13 @@
+import { Controller, Get, UseGuards } from '@nestjs/common';
+import { AuthGuard } from '@nestjs/passport';
+
+@Controller()
+export class UserController {
+ constructor() {}
+
+ @Get('profile')
+ @UseGuards(AuthGuard('jwt'))
+ getProfile(): string {
+ return 'OK';
+ }
+}
diff --git a/api/src/users/users.module.ts b/api/src/users/users.module.ts
index 3f16c4be..fa421ea8 100644
--- a/api/src/users/users.module.ts
+++ b/api/src/users/users.module.ts
@@ -2,12 +2,21 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersService } from './users.service';
+import { UserController } from './user.controller';
+import { JwtStrategy } from './jwt.strategy';
+import { PassportModule } from '@nestjs/passport';
@Module({
// forFeature is what triggers the entity to be loaded into the database management system as a persistant object type
- imports: [TypeOrmModule.forFeature([User])],
- providers: [UsersService],
- controllers: [],
+ imports: [
+ TypeOrmModule.forFeature([User]),
+ PassportModule.register({ defaultStrategy: 'jwt' })
+ ],
+ providers: [
+ UsersService,
+ JwtStrategy
+ ],
+ controllers: [UserController],
exports: [UsersService],
})
export class UsersModule {}
diff --git a/frontend/package.json b/frontend/package.json
index f2d33d94..045795f8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -4,16 +4,19 @@
"version": "0.0.0",
"type": "module",
"scripts": {
- "dev": "vite --open",
+ "dev": "vite --open --port 8080",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
+ "@types/js-cookie": "^3.0.6",
"autoprefixer": "^10.4.16",
"flowbite": "^2.2.0",
"flowbite-react": "^0.7.0",
"jose": "^5.1.3",
+ "js-cookie": "^3.0.5",
+ "oauth4webapi": "^2.4.0",
"postcss": "^8.4.32",
"react": "^18.2.0",
"react-cookie": "^6.1.1",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 2307dcc1..93d2d8f2 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,9 +1,20 @@
+import { Button } from "flowbite-react"
+import { beginAuthFlow, onRedirect } from "./util/oauth"
+import { useEffect } from "react"
function App() {
+ useEffect(() => {
+ const urlParams = new URLSearchParams(window.location.search);
+
+ if (urlParams.get('code') !== null) {
+ onRedirect()
+ }
+ }, []);
return (
Nothing to see here yet.
+
)
}
diff --git a/frontend/src/util/oauth.ts b/frontend/src/util/oauth.ts
new file mode 100644
index 00000000..2741bb2f
--- /dev/null
+++ b/frontend/src/util/oauth.ts
@@ -0,0 +1,87 @@
+import * as oauth from 'oauth4webapi';
+import Cookies from 'js-cookie';
+
+const ISSUER = new URL('https://id.realliance.net/application/o/profile/');
+const REDIRECT_URI = import.meta.env.PROD ? "https://profile.realliance.net" : "http://localhost:8080";
+
+const as = await oauth
+ .discoveryRequest(ISSUER)
+ .then((response) => oauth.processDiscoveryResponse(ISSUER, response));
+
+const client: oauth.Client = {
+ client_id: 'LNXdUuOZUue5HPlw8Vyglo83sIYndFaGUCIdQrSZ',
+ token_endpoint_auth_method: 'none',
+ }
+
+export async function beginAuthFlow() {
+
+
+ if (as.code_challenge_methods_supported?.includes('S256') !== true) {
+ // This example assumes S256 PKCE support is signalled
+ // If it isn't supported, random `nonce` must be used for CSRF protection.
+ throw new Error("S256 PKCE not supported");
+ }
+
+ const code_verifier = oauth.generateRandomCodeVerifier()
+ const code_challenge = await oauth.calculatePKCECodeChallenge(code_verifier)
+ const code_challenge_method = 'S256'
+
+ Cookies.remove('codeVerifier');
+ Cookies.set('codeVerifier', code_verifier);
+
+ const authorizationUrl = new URL(as.authorization_endpoint!)
+ authorizationUrl.searchParams.set('client_id', client.client_id)
+ authorizationUrl.searchParams.set('code_challenge', code_challenge)
+ authorizationUrl.searchParams.set('code_challenge_method', code_challenge_method)
+ authorizationUrl.searchParams.set('redirect_uri', REDIRECT_URI)
+ authorizationUrl.searchParams.set('response_type', 'code')
+ authorizationUrl.searchParams.set('scope', 'openid profile')
+
+ window.location.href = authorizationUrl.toString();
+}
+
+export async function onRedirect() {
+ const currentUrl = new URL(window.location.href);
+ const params = oauth.validateAuthResponse(as, client, currentUrl, oauth.skipStateCheck)
+ if (oauth.isOAuth2Error(params)) {
+ console.log('error', params)
+ throw new Error("Oauth2 Failed") // Handle OAuth 2.0 redirect error
+ }
+
+ const code_verifier = Cookies.get('codeVerifier') ?? "";
+ Cookies.remove('codeVerifier');
+
+ const response = await oauth.authorizationCodeGrantRequest(
+ as,
+ client,
+ params,
+ REDIRECT_URI,
+ code_verifier,
+ )
+
+ let challenges: oauth.WWWAuthenticateChallenge[] | undefined
+ if ((challenges = oauth.parseWwwAuthenticateChallenges(response))) {
+ for (const challenge of challenges) {
+ console.log('challenge', challenge)
+ }
+ throw new Error() // Handle www-authenticate challenges as needed
+ }
+
+ const result = await oauth.processAuthorizationCodeOpenIDResponse(as, client, response)
+ if (oauth.isOAuth2Error(result)) {
+ console.log('error', result)
+ throw new Error() // Handle OAuth 2.0 response body error
+ }
+
+ console.log('result', result)
+ const claims = oauth.getValidatedIdTokenClaims(result)
+ console.log('ID Token Claims', claims)
+
+ const res = await fetch('http://localhost:3000/api/profile', {
+ headers: {
+ "Authorization": `Bearer ${result.access_token}`,
+ }
+ });
+
+ console.log(await res.text());
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 8df0e7c5..874ffe43 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1234,6 +1234,11 @@
"@types/jsonwebtoken" "9.0.5"
jsonwebtoken "9.0.2"
+"@nestjs/passport@^10.0.3":
+ version "10.0.3"
+ resolved "https://registry.yarnpkg.com/@nestjs/passport/-/passport-10.0.3.tgz#26ec5b2167d364e04962c115fcef80d10e185367"
+ integrity sha512-znJ9Y4S8ZDVY+j4doWAJ8EuuVO7SkQN3yOBmzxbGaXbvcSwFDAdGJ+OMCg52NdzIO4tQoN4pYKx8W6M0ArfFRQ==
+
"@nestjs/platform-express@^10.0.0":
version "10.2.10"
resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.2.10.tgz#6ff94e5a3f3a15ff39d8044e966fd4ceecd8d068"
@@ -1959,12 +1964,17 @@
expect "^29.0.0"
pretty-format "^29.0.0"
+"@types/js-cookie@^3.0.6":
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.6.tgz#a04ca19e877687bd449f5ad37d33b104b71fdf95"
+ integrity sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==
+
"@types/json-schema@*", "@types/json-schema@^7.0.12", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.15"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
-"@types/jsonwebtoken@9.0.5":
+"@types/jsonwebtoken@*", "@types/jsonwebtoken@9.0.5", "@types/jsonwebtoken@^9.0.2":
version "9.0.5"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.5.tgz#0bd9b841c9e6c5a937c17656e2368f65da025588"
integrity sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==
@@ -2024,6 +2034,30 @@
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.3.tgz#705bb349e789efa06f43f128cef51240753424cb"
integrity sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==
+"@types/passport-jwt@^3.0.13":
+ version "3.0.13"
+ resolved "https://registry.yarnpkg.com/@types/passport-jwt/-/passport-jwt-3.0.13.tgz#119267d2fc1af7d274a512731146183de5f2b53f"
+ integrity sha512-fjHaC6Bv8EpMMqzTnHP32SXlZGaNfBPC/Po5dmRGYi2Ky7ljXPbGnOy+SxZqa6iZvFgVhoJ1915Re3m93zmcfA==
+ dependencies:
+ "@types/express" "*"
+ "@types/jsonwebtoken" "*"
+ "@types/passport-strategy" "*"
+
+"@types/passport-strategy@*":
+ version "0.2.38"
+ resolved "https://registry.yarnpkg.com/@types/passport-strategy/-/passport-strategy-0.2.38.tgz#482abba0b165cd4553ec8b748f30b022bd6c04d3"
+ integrity sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==
+ dependencies:
+ "@types/express" "*"
+ "@types/passport" "*"
+
+"@types/passport@*":
+ version "1.0.16"
+ resolved "https://registry.yarnpkg.com/@types/passport/-/passport-1.0.16.tgz#5a2918b180a16924c4d75c31254c31cdca5ce6cf"
+ integrity sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==
+ dependencies:
+ "@types/express" "*"
+
"@types/prop-types@*":
version "15.7.11"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
@@ -5837,11 +5871,21 @@ jiti@^1.19.1:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+jose@^4.14.6:
+ version "4.15.4"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.4.tgz#02a9a763803e3872cf55f29ecef0dfdcc218cc03"
+ integrity sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==
+
jose@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/jose/-/jose-5.1.3.tgz#303959d85c51b5cb14725f930270b72be56abdca"
integrity sha512-GPExOkcMsCLBTi1YetY2LmkoY559fss0+0KVa6kOfb2YFe84nAM7Nm/XzuZozah4iHgmBGrCOHL5/cy670SBRw==
+js-cookie@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
+ integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -5916,7 +5960,7 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
-jsonwebtoken@9.0.2:
+jsonwebtoken@9.0.2, jsonwebtoken@^9.0.0:
version "9.0.2"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3"
integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==
@@ -5941,6 +5985,18 @@ jwa@^1.4.1:
ecdsa-sig-formatter "1.0.11"
safe-buffer "^5.0.1"
+jwks-rsa@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/jwks-rsa/-/jwks-rsa-3.1.0.tgz#50406f23e38c9b2682cd437f824d7d61aa983171"
+ integrity sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==
+ dependencies:
+ "@types/express" "^4.17.17"
+ "@types/jsonwebtoken" "^9.0.2"
+ debug "^4.3.4"
+ jose "^4.14.6"
+ limiter "^1.1.5"
+ lru-memoizer "^2.2.0"
+
jws@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
@@ -6013,6 +6069,11 @@ lilconfig@^3.0.0:
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.0.0.tgz#f8067feb033b5b74dab4602a5f5029420be749bc"
integrity sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==
+limiter@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2"
+ integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==
+
lines-and-columns@^1.1.6:
version "1.2.4"
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
@@ -6057,6 +6118,11 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
+lodash.clonedeep@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+ integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
@@ -6186,6 +6252,22 @@ lru-cache@^6.0.0:
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484"
integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==
+lru-cache@~4.0.0:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e"
+ integrity sha512-uQw9OqphAGiZhkuPlpFGmdTU2tEuhxTourM/19qGJrxBPHAr/f8BT1a0i/lOclESnGatdJG/UCkP9kZB/Lh1iw==
+ dependencies:
+ pseudomap "^1.0.1"
+ yallist "^2.0.0"
+
+lru-memoizer@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.2.0.tgz#b9d90c91637b4b1a423ef76f3156566691293df8"
+ integrity sha512-QfOZ6jNkxCcM/BkIPnFsqDhtrazLRsghi9mBwFAzol5GCvj4EkFT899Za3+QwikCg5sRX8JstioBDwOxEyzaNw==
+ dependencies:
+ lodash.clonedeep "^4.5.0"
+ lru-cache "~4.0.0"
+
macos-release@^2.5.0:
version "2.5.1"
resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.1.tgz#bccac4a8f7b93163a8d163b8ebf385b3c5f55bf9"
@@ -7464,6 +7546,11 @@ npmlog@^6.0.0:
gauge "^4.0.3"
set-blocking "^2.0.0"
+oauth4webapi@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.4.0.tgz#2a5e75996a33878cced3f367753aa42f21d36e27"
+ integrity sha512-ZWl8ov8HeGVyc9Icl1cag76HvIcDAp23eIIT+UVGir+dEu8BMgMlvZeZwqLVd0P8DqaumH4N+QLQXN69G1QjSA==
+
object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@@ -7670,6 +7757,28 @@ pascal-case@^3.1.2:
no-case "^3.0.4"
tslib "^2.0.3"
+passport-jwt@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.1.tgz#c443795eff322c38d173faa0a3c481479646ec3d"
+ integrity sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==
+ dependencies:
+ jsonwebtoken "^9.0.0"
+ passport-strategy "^1.0.0"
+
+passport-strategy@1.x.x, passport-strategy@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
+ integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==
+
+passport@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/passport/-/passport-0.7.0.tgz#3688415a59a48cf8068417a8a8092d4492ca3a05"
+ integrity sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==
+ dependencies:
+ passport-strategy "1.x.x"
+ pause "0.0.1"
+ utils-merge "^1.0.1"
+
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -7718,6 +7827,11 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+pause@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
+ integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==
+
peek-readable@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-5.0.0.tgz#7ead2aff25dc40458c60347ea76cfdfd63efdfec"
@@ -7923,7 +8037,7 @@ proxy-addr@~2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
-pseudomap@^1.0.2:
+pseudomap@^1.0.1, pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==
@@ -9543,7 +9657,7 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-utils-merge@1.0.1:
+utils-merge@1.0.1, utils-merge@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
@@ -9814,7 +9928,7 @@ y18n@^5.0.5:
resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
-yallist@^2.1.2:
+yallist@^2.0.0, yallist@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==