mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-09 20:12:26 +10:00
Implement OpenID Connect Authentication Strategy (works with Keycloak, Authentik etc.)
This commit is contained in:
@ -68,3 +68,12 @@ STORAGE_SKIP_BUCKET_CHECK=false
|
||||
# GOOGLE_CLIENT_ID=
|
||||
# GOOGLE_CLIENT_SECRET=
|
||||
# GOOGLE_CALLBACK_URL=http://localhost:5173/api/auth/google/callback
|
||||
|
||||
# OpenID (Optional)
|
||||
# OPENID_AUTHORIZATION_URL=
|
||||
# OPENID_CALLBACK_URL=http://localhost:5173/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID=
|
||||
# OPENID_CLIENT_SECRET=
|
||||
# OPENID_ISSUER=
|
||||
# OPENID_TOKEN_URL=
|
||||
# OPENID_USER_INFO_URL=
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { t } from "@lingui/macro";
|
||||
import { GithubLogo, GoogleLogo } from "@phosphor-icons/react";
|
||||
import { Fingerprint, GithubLogo, GoogleLogo } from "@phosphor-icons/react";
|
||||
import { Button } from "@reactive-resume/ui";
|
||||
|
||||
import { useAuthProviders } from "@/client/services/auth/providers";
|
||||
@ -32,6 +32,19 @@ export const SocialAuth = () => {
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{providers.includes("openid") && (
|
||||
<Button
|
||||
asChild
|
||||
size="lg"
|
||||
className="w-full !bg-[#dc2626] !text-white hover:!bg-[#dc2626]/80"
|
||||
>
|
||||
<a href="/api/auth/openid">
|
||||
<Fingerprint className="mr-3 size-4" />
|
||||
{t`OpenID`}
|
||||
</a>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -35,6 +35,7 @@ import { GitHubGuard } from "./guards/github.guard";
|
||||
import { GoogleGuard } from "./guards/google.guard";
|
||||
import { JwtGuard } from "./guards/jwt.guard";
|
||||
import { LocalGuard } from "./guards/local.guard";
|
||||
import { OpenIDGuard } from "./guards/openid.guard";
|
||||
import { RefreshGuard } from "./guards/refresh.guard";
|
||||
import { TwoFactorGuard } from "./guards/two-factor.guard";
|
||||
import { getCookieOptions } from "./utils/cookie";
|
||||
@ -147,6 +148,23 @@ export class AuthController {
|
||||
return this.handleAuthenticationResponse(user, response, false, true);
|
||||
}
|
||||
|
||||
@ApiTags("OAuth", "OpenID")
|
||||
@Get("openid")
|
||||
@UseGuards(OpenIDGuard)
|
||||
openidLogin() {
|
||||
return;
|
||||
}
|
||||
|
||||
@ApiTags("OAuth", "OpenID")
|
||||
@Get("openid/callback")
|
||||
@UseGuards(OpenIDGuard)
|
||||
async openidCallback(
|
||||
@User() user: UserWithSecrets,
|
||||
@Res({ passthrough: true }) response: Response,
|
||||
) {
|
||||
return this.handleAuthenticationResponse(user, response, false, true);
|
||||
}
|
||||
|
||||
@Post("refresh")
|
||||
@UseGuards(RefreshGuard)
|
||||
async refresh(@User() user: UserWithSecrets, @Res({ passthrough: true }) response: Response) {
|
||||
|
||||
@ -14,6 +14,7 @@ import { GitHubStrategy } from "./strategy/github.strategy";
|
||||
import { GoogleStrategy } from "./strategy/google.strategy";
|
||||
import { JwtStrategy } from "./strategy/jwt.strategy";
|
||||
import { LocalStrategy } from "./strategy/local.strategy";
|
||||
import { OpenIDStrategy } from "./strategy/openid.strategy";
|
||||
import { RefreshStrategy } from "./strategy/refresh.strategy";
|
||||
import { TwoFactorStrategy } from "./strategy/two-factor.strategy";
|
||||
|
||||
@ -63,6 +64,35 @@ export class AuthModule {
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
provide: OpenIDStrategy,
|
||||
inject: [ConfigService, UserService],
|
||||
useFactory: (configService: ConfigService<Config>, userService: UserService) => {
|
||||
try {
|
||||
const authorizationURL = configService.getOrThrow("OPENID_AUTHORIZATION_URL");
|
||||
const callbackURL = configService.getOrThrow("OPENID_CALLBACK_URL");
|
||||
const clientID = configService.getOrThrow("OPENID_CLIENT_ID");
|
||||
const clientSecret = configService.getOrThrow("OPENID_CLIENT_SECRET");
|
||||
const issuer = configService.getOrThrow("OPENID_ISSUER");
|
||||
const tokenURL = configService.getOrThrow("OPENID_TOKEN_URL");
|
||||
const userInfoURL = configService.getOrThrow("OPENID_USER_INFO_URL");
|
||||
|
||||
return new OpenIDStrategy(
|
||||
authorizationURL,
|
||||
callbackURL,
|
||||
clientID,
|
||||
clientSecret,
|
||||
issuer,
|
||||
tokenURL,
|
||||
userInfoURL,
|
||||
userService,
|
||||
);
|
||||
} catch {
|
||||
return new DummyStrategy();
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
exports: [AuthService],
|
||||
};
|
||||
|
||||
@ -199,6 +199,14 @@ export class AuthService {
|
||||
providers.push("google");
|
||||
}
|
||||
|
||||
if (
|
||||
this.configService.get("OPENID_CLIENT_ID") &&
|
||||
this.configService.get("OPENID_CLIENT_SECRET") &&
|
||||
this.configService.get("OPENID_CALLBACK_URL")
|
||||
) {
|
||||
providers.push("openid");
|
||||
}
|
||||
|
||||
return providers;
|
||||
}
|
||||
|
||||
|
||||
5
apps/server/src/auth/guards/openid.guard.ts
Normal file
5
apps/server/src/auth/guards/openid.guard.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
|
||||
@Injectable()
|
||||
export class OpenIDGuard extends AuthGuard("openid") {}
|
||||
74
apps/server/src/auth/strategy/openid.strategy.ts
Normal file
74
apps/server/src/auth/strategy/openid.strategy.ts
Normal file
@ -0,0 +1,74 @@
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { User } from "@prisma/client";
|
||||
import { ErrorMessage, processUsername } from "@reactive-resume/utils";
|
||||
import { Profile, Strategy, StrategyOptions } from "passport-openidconnect";
|
||||
|
||||
import { UserService } from "@/server/user/user.service";
|
||||
|
||||
@Injectable()
|
||||
export class OpenIDStrategy extends PassportStrategy(Strategy, "openid") {
|
||||
constructor(
|
||||
readonly authorizationURL: string,
|
||||
readonly callbackURL: string,
|
||||
readonly clientID: string,
|
||||
readonly clientSecret: string,
|
||||
readonly issuer: string,
|
||||
readonly tokenURL: string,
|
||||
readonly userInfoURL: string,
|
||||
private readonly userService: UserService,
|
||||
) {
|
||||
super({
|
||||
authorizationURL,
|
||||
callbackURL,
|
||||
clientID,
|
||||
clientSecret,
|
||||
issuer,
|
||||
tokenURL,
|
||||
userInfoURL,
|
||||
scope: "openid email profile",
|
||||
} as StrategyOptions);
|
||||
}
|
||||
|
||||
async validate(
|
||||
issuer: unknown,
|
||||
profile: Profile,
|
||||
done: (err?: string | Error | null, user?: Express.User, info?: unknown) => void,
|
||||
) {
|
||||
const { displayName, emails, photos, username } = profile;
|
||||
|
||||
const email = emails?.[0].value ?? `${username}@github.com`;
|
||||
const picture = photos?.[0].value;
|
||||
|
||||
let user: User | null = null;
|
||||
|
||||
if (!email) throw new BadRequestException(ErrorMessage.InvalidCredentials);
|
||||
|
||||
try {
|
||||
const user =
|
||||
(await this.userService.findOneByIdentifier(email)) ??
|
||||
(username && (await this.userService.findOneByIdentifier(username)));
|
||||
|
||||
if (!user) throw new Error(ErrorMessage.InvalidCredentials);
|
||||
|
||||
done(null, user);
|
||||
} catch {
|
||||
try {
|
||||
user = await this.userService.create({
|
||||
email,
|
||||
picture,
|
||||
locale: "en-US",
|
||||
name: displayName,
|
||||
provider: "openid",
|
||||
emailVerified: true, // auto-verify emails
|
||||
username: processUsername(username ?? email.split("@")[0]),
|
||||
secrets: { create: {} },
|
||||
});
|
||||
|
||||
done(null, user);
|
||||
} catch {
|
||||
throw new BadRequestException(ErrorMessage.UserAlreadyExists);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -63,15 +63,24 @@ export const configSchema = z.object({
|
||||
.default("false")
|
||||
.transform((s) => s !== "false" && s !== "0"),
|
||||
|
||||
// GitHub (OAuth)
|
||||
// GitHub (OAuth, Optional)
|
||||
GITHUB_CLIENT_ID: z.string().optional(),
|
||||
GITHUB_CLIENT_SECRET: z.string().optional(),
|
||||
GITHUB_CALLBACK_URL: z.string().url().optional(),
|
||||
|
||||
// Google (OAuth)
|
||||
// Google (OAuth, Optional)
|
||||
GOOGLE_CLIENT_ID: z.string().optional(),
|
||||
GOOGLE_CLIENT_SECRET: z.string().optional(),
|
||||
GOOGLE_CALLBACK_URL: z.string().url().optional(),
|
||||
|
||||
// OpenID (Optional)
|
||||
OPENID_AUTHORIZATION_URL: z.string().url().optional(),
|
||||
OPENID_CALLBACK_URL: z.string().url().optional(),
|
||||
OPENID_CLIENT_ID: z.string().optional(),
|
||||
OPENID_CLIENT_SECRET: z.string().optional(),
|
||||
OPENID_ISSUER: z.string().optional(),
|
||||
OPENID_TOKEN_URL: z.string().url().optional(),
|
||||
OPENID_USER_INFO_URL: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export type Config = z.infer<typeof configSchema>;
|
||||
|
||||
@ -4,6 +4,7 @@ import { NestFactory } from "@nestjs/core";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger";
|
||||
import cookieParser from "cookie-parser";
|
||||
import session from "express-session";
|
||||
import helmet from "helmet";
|
||||
import { patchNestJsSwagger } from "nestjs-zod";
|
||||
|
||||
@ -21,6 +22,15 @@ async function bootstrap() {
|
||||
// Cookie Parser
|
||||
app.use(cookieParser());
|
||||
|
||||
// Session
|
||||
app.use(
|
||||
session({
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
secret: configService.getOrThrow("ACCESS_TOKEN_SECRET"),
|
||||
}),
|
||||
);
|
||||
|
||||
// CORS
|
||||
app.enableCors({
|
||||
credentials: true,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { createZodDto } from "nestjs-zod/dto";
|
||||
import { z } from "zod";
|
||||
|
||||
const authProvidersSchema = z.array(z.enum(["email", "github", "google"]));
|
||||
const authProvidersSchema = z.array(z.enum(["email", "github", "google", "openid"]));
|
||||
|
||||
export class AuthProvidersDto extends createZodDto(authProvidersSchema) {}
|
||||
|
||||
@ -26,7 +26,7 @@ export const userSchema = z.object({
|
||||
locale: z.string().default("en-US"),
|
||||
emailVerified: z.boolean().default(false),
|
||||
twoFactorEnabled: z.boolean().default(false),
|
||||
provider: z.enum(["email", "github", "google"]).default("email"),
|
||||
provider: z.enum(["email", "github", "google", "openid"]).default("email"),
|
||||
createdAt: dateSchema,
|
||||
updatedAt: dateSchema,
|
||||
});
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@reactive-resume/source",
|
||||
"description": "A free and open-source resume builder that simplifies the process of creating, updating, and sharing your resume.",
|
||||
"version": "4.3.6",
|
||||
"version": "4.3.7",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"author": {
|
||||
@ -62,6 +62,7 @@
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/cookie-parser": "^1.4.8",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/express-session": "^1.18.1",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/lodash.debounce": "^4.0.9",
|
||||
@ -75,6 +76,7 @@
|
||||
"@types/passport-github2": "^1.2.9",
|
||||
"@types/passport-google-oauth20": "^2.0.16",
|
||||
"@types/passport-local": "^1.0.38",
|
||||
"@types/passport-openidconnect": "^0.1.3",
|
||||
"@types/prismjs": "^1.26.5",
|
||||
"@types/react": "^18.3.18",
|
||||
"@types/react-dom": "^18.3.5",
|
||||
@ -171,7 +173,7 @@
|
||||
"@radix-ui/react-visually-hidden": "^1.1.1",
|
||||
"@sindresorhus/slugify": "^2.2.1",
|
||||
"@swc/helpers": "^0.5.15",
|
||||
"@tanstack/react-query": "^5.64.0",
|
||||
"@tanstack/react-query": "^5.64.1",
|
||||
"@tiptap/extension-highlight": "^2.11.2",
|
||||
"@tiptap/extension-image": "^2.11.2",
|
||||
"@tiptap/extension-link": "^2.11.2",
|
||||
@ -191,6 +193,7 @@
|
||||
"cookie-parser": "^1.4.7",
|
||||
"dayjs": "^1.11.13",
|
||||
"deepmerge": "^4.3.1",
|
||||
"express-session": "^1.18.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"framer-motion": "^11.17.0",
|
||||
"fuzzy": "^0.1.3",
|
||||
@ -214,6 +217,7 @@
|
||||
"passport-google-oauth20": "^2.0.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"passport-local": "^1.0.0",
|
||||
"passport-openidconnect": "^0.1.2",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"prisma": "^5.22.0",
|
||||
"prismjs": "^1.29.0",
|
||||
|
||||
96
pnpm-lock.yaml
generated
96
pnpm-lock.yaml
generated
@ -162,8 +162,8 @@ importers:
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.15
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.64.0
|
||||
version: 5.64.0(react@18.3.1)
|
||||
specifier: ^5.64.1
|
||||
version: 5.64.1(react@18.3.1)
|
||||
'@tiptap/extension-highlight':
|
||||
specifier: ^2.11.2
|
||||
version: 2.11.2(@tiptap/core@2.11.2(@tiptap/pm@2.11.2))
|
||||
@ -221,6 +221,9 @@ importers:
|
||||
deepmerge:
|
||||
specifier: ^4.3.1
|
||||
version: 4.3.1
|
||||
express-session:
|
||||
specifier: ^1.18.1
|
||||
version: 1.18.1
|
||||
file-saver:
|
||||
specifier: ^2.0.5
|
||||
version: 2.0.5
|
||||
@ -290,6 +293,9 @@ importers:
|
||||
passport-local:
|
||||
specifier: ^1.0.0
|
||||
version: 1.0.0
|
||||
passport-openidconnect:
|
||||
specifier: ^0.1.2
|
||||
version: 0.1.2
|
||||
pdf-lib:
|
||||
specifier: ^1.17.1
|
||||
version: 1.17.1
|
||||
@ -474,6 +480,9 @@ importers:
|
||||
'@types/express':
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
'@types/express-session':
|
||||
specifier: ^1.18.1
|
||||
version: 1.18.1
|
||||
'@types/file-saver':
|
||||
specifier: ^2.0.7
|
||||
version: 2.0.7
|
||||
@ -513,6 +522,9 @@ importers:
|
||||
'@types/passport-local':
|
||||
specifier: ^1.0.38
|
||||
version: 1.0.38
|
||||
'@types/passport-openidconnect':
|
||||
specifier: ^0.1.3
|
||||
version: 0.1.3
|
||||
'@types/prismjs':
|
||||
specifier: ^1.26.5
|
||||
version: 1.26.5
|
||||
@ -3978,11 +3990,11 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
|
||||
'@tanstack/query-core@5.64.0':
|
||||
resolution: {integrity: sha512-/MPJt/AaaMzdWJZTafgMyYhEX/lGjQrNz8+NDQSk8fNoU5PHqh05FhQaBrEQafW2PeBHsRbefEf//qKMiSAbQQ==}
|
||||
'@tanstack/query-core@5.64.1':
|
||||
resolution: {integrity: sha512-978Wx4Wl4UJZbmvU/rkaM9cQtXXrbhK0lsz/UZhYIbyKYA8E4LdomTwyh2GHZ4oU0BKKoDH4YlKk2VscCUgNmg==}
|
||||
|
||||
'@tanstack/react-query@5.64.0':
|
||||
resolution: {integrity: sha512-tBMzlROROUcTDMpDt1NC3n9ndKnJHPB3RCpa6Bf9f31TFvqhLz879x8jldtKU+6IwMSw1Pn4K1AKA+2SYyA6TA==}
|
||||
'@tanstack/react-query@5.64.1':
|
||||
resolution: {integrity: sha512-vW5ggHpIO2Yjj44b4sB+Fd3cdnlMJppXRBJkEHvld6FXh3j5dwWJoQo7mGtKI2RbSFyiyu/PhGAy0+Vv5ev9Eg==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
|
||||
@ -4261,6 +4273,9 @@ packages:
|
||||
'@types/express-serve-static-core@4.17.43':
|
||||
resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
|
||||
|
||||
'@types/express-session@1.18.1':
|
||||
resolution: {integrity: sha512-S6TkD/lljxDlQ2u/4A70luD8/ZxZcrU5pQwI1rVXCiaVIywoFgbA+PIUNDjPhQpPdK0dGleLtYc/y7XWBfclBg==}
|
||||
|
||||
'@types/express@4.17.21':
|
||||
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
|
||||
|
||||
@ -4402,6 +4417,9 @@ packages:
|
||||
'@types/passport-oauth2@1.4.15':
|
||||
resolution: {integrity: sha512-9cUTP/HStNSZmhxXGuRrBJfEWzIEJRub2eyJu3CvkA+8HAMc9W3aKdFhVq+Qz1hi42qn+GvSAnz3zwacDSYWpw==}
|
||||
|
||||
'@types/passport-openidconnect@0.1.3':
|
||||
resolution: {integrity: sha512-k1Ni7bG/9OZNo2Qpjg2W6GajL+pww6ZPaNWMXfpteCX4dXf4QgaZLt2hjR5IiPrqwBT9+W8KjCTJ/uhGIoBx/g==}
|
||||
|
||||
'@types/passport-strategy@0.2.38':
|
||||
resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==}
|
||||
|
||||
@ -5600,6 +5618,9 @@ packages:
|
||||
cookie-signature@1.0.6:
|
||||
resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
|
||||
|
||||
cookie-signature@1.0.7:
|
||||
resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==}
|
||||
|
||||
cookie@0.6.0:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
@ -6501,6 +6522,10 @@ packages:
|
||||
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
|
||||
express-session@1.18.1:
|
||||
resolution: {integrity: sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
express@4.19.2:
|
||||
resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==}
|
||||
engines: {node: '>= 0.10.0'}
|
||||
@ -8897,6 +8922,10 @@ packages:
|
||||
resolution: {integrity: sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
passport-openidconnect@0.1.2:
|
||||
resolution: {integrity: sha512-JX3rTyW+KFZ/E9OF/IpXJPbyLO9vGzcmXB5FgSP2jfL3LGKJPdV7zUE8rWeKeeI/iueQggOeFa3onrCmhxXZTg==}
|
||||
engines: {node: '>= 0.6.0'}
|
||||
|
||||
passport-strategy@1.0.0:
|
||||
resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
@ -9614,6 +9643,10 @@ packages:
|
||||
ramda@0.27.2:
|
||||
resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==}
|
||||
|
||||
random-bytes@1.0.0:
|
||||
resolution: {integrity: sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
|
||||
@ -10891,6 +10924,10 @@ packages:
|
||||
engines: {node: '>=0.8.0'}
|
||||
hasBin: true
|
||||
|
||||
uid-safe@2.1.5:
|
||||
resolution: {integrity: sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
uid2@0.0.4:
|
||||
resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==}
|
||||
|
||||
@ -12739,7 +12776,7 @@ snapshots:
|
||||
'@eslint/eslintrc@2.1.4':
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.3.6
|
||||
debug: 4.4.0
|
||||
espree: 9.6.1
|
||||
globals: 13.24.0
|
||||
ignore: 5.3.1
|
||||
@ -12808,7 +12845,7 @@ snapshots:
|
||||
'@humanwhocodes/config-array@0.11.14':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
debug: 4.3.6
|
||||
debug: 4.4.0
|
||||
minimatch: 3.1.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -15661,11 +15698,11 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@tanstack/query-core@5.64.0': {}
|
||||
'@tanstack/query-core@5.64.1': {}
|
||||
|
||||
'@tanstack/react-query@5.64.0(react@18.3.1)':
|
||||
'@tanstack/react-query@5.64.1(react@18.3.1)':
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.64.0
|
||||
'@tanstack/query-core': 5.64.1
|
||||
react: 18.3.1
|
||||
|
||||
'@testing-library/dom@10.1.0':
|
||||
@ -15984,6 +16021,10 @@ snapshots:
|
||||
'@types/range-parser': 1.2.7
|
||||
'@types/send': 0.17.4
|
||||
|
||||
'@types/express-session@1.18.1':
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
|
||||
'@types/express@4.17.21':
|
||||
dependencies:
|
||||
'@types/body-parser': 1.19.5
|
||||
@ -16164,6 +16205,13 @@ snapshots:
|
||||
'@types/oauth': 0.9.4
|
||||
'@types/passport': 1.0.17
|
||||
|
||||
'@types/passport-openidconnect@0.1.3':
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
'@types/oauth': 0.9.4
|
||||
'@types/passport': 1.0.17
|
||||
'@types/passport-strategy': 0.2.38
|
||||
|
||||
'@types/passport-strategy@0.2.38':
|
||||
dependencies:
|
||||
'@types/express': 4.17.21
|
||||
@ -17621,6 +17669,8 @@ snapshots:
|
||||
|
||||
cookie-signature@1.0.6: {}
|
||||
|
||||
cookie-signature@1.0.7: {}
|
||||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
cookie@0.7.1: {}
|
||||
@ -18737,6 +18787,19 @@ snapshots:
|
||||
jest-message-util: 29.7.0
|
||||
jest-util: 29.7.0
|
||||
|
||||
express-session@1.18.1:
|
||||
dependencies:
|
||||
cookie: 0.7.2
|
||||
cookie-signature: 1.0.7
|
||||
debug: 2.6.9
|
||||
depd: 2.0.0
|
||||
on-headers: 1.0.2
|
||||
parseurl: 1.3.3
|
||||
safe-buffer: 5.2.1
|
||||
uid-safe: 2.1.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
express@4.19.2:
|
||||
dependencies:
|
||||
accepts: 1.3.8
|
||||
@ -21918,6 +21981,11 @@ snapshots:
|
||||
uid2: 0.0.4
|
||||
utils-merge: 1.0.1
|
||||
|
||||
passport-openidconnect@0.1.2:
|
||||
dependencies:
|
||||
oauth: 0.10.0
|
||||
passport-strategy: 1.0.0
|
||||
|
||||
passport-strategy@1.0.0: {}
|
||||
|
||||
passport@0.7.0:
|
||||
@ -22646,6 +22714,8 @@ snapshots:
|
||||
|
||||
ramda@0.27.2: {}
|
||||
|
||||
random-bytes@1.0.0: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
@ -24117,6 +24187,10 @@ snapshots:
|
||||
uglify-js@3.17.4:
|
||||
optional: true
|
||||
|
||||
uid-safe@2.1.5:
|
||||
dependencies:
|
||||
random-bytes: 1.0.0
|
||||
|
||||
uid2@0.0.4: {}
|
||||
|
||||
uid@2.0.2:
|
||||
|
||||
@ -107,6 +107,15 @@ services:
|
||||
# GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
# GOOGLE_CALLBACK_URL: https://example.com/api/auth/google/callback
|
||||
|
||||
# -- OpenID (Optional) --
|
||||
# OPENID_AUTHORIZATION_URL:
|
||||
# OPENID_CALLBACK_URL: https://example.com/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID:
|
||||
# OPENID_CLIENT_SECRET:
|
||||
# OPENID_ISSUER:
|
||||
# OPENID_TOKEN_URL:
|
||||
# OPENID_USER_INFO_URL:
|
||||
|
||||
nginx:
|
||||
image: jc21/nginx-proxy-manager
|
||||
restart: always
|
||||
|
||||
@ -106,6 +106,15 @@ services:
|
||||
# GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
# GOOGLE_CALLBACK_URL: http://localhost:3000/api/auth/google/callback
|
||||
|
||||
# -- OpenID (Optional) --
|
||||
# OPENID_AUTHORIZATION_URL:
|
||||
# OPENID_CALLBACK_URL: http://localhost:3000/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID:
|
||||
# OPENID_CLIENT_SECRET:
|
||||
# OPENID_ISSUER:
|
||||
# OPENID_TOKEN_URL:
|
||||
# OPENID_USER_INFO_URL:
|
||||
|
||||
volumes:
|
||||
minio_data:
|
||||
postgres_data:
|
||||
|
||||
@ -125,6 +125,15 @@ services:
|
||||
# GOOGLE_CLIENT_ID: google_client_id
|
||||
# GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
# GOOGLE_CALLBACK_URL: https://example.com/api/auth/google/callback
|
||||
|
||||
# -- OpenID (Optional) --
|
||||
# OPENID_AUTHORIZATION_URL:
|
||||
# OPENID_CALLBACK_URL: https://example.com/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID:
|
||||
# OPENID_CLIENT_SECRET:
|
||||
# OPENID_ISSUER:
|
||||
# OPENID_TOKEN_URL:
|
||||
# OPENID_USER_INFO_URL:
|
||||
deploy:
|
||||
replicas: 2
|
||||
restart_policy:
|
||||
|
||||
@ -114,6 +114,15 @@ services:
|
||||
# GOOGLE_CLIENT_ID: google_client_id
|
||||
# GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
# GOOGLE_CALLBACK_URL: https://example.com/api/auth/google/callback
|
||||
|
||||
# -- OpenID (Optional) --
|
||||
# OPENID_AUTHORIZATION_URL:
|
||||
# OPENID_CALLBACK_URL: https://example.com/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID:
|
||||
# OPENID_CLIENT_SECRET:
|
||||
# OPENID_ISSUER:
|
||||
# OPENID_TOKEN_URL:
|
||||
# OPENID_USER_INFO_URL:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.app.rule=Host(`example.com`)
|
||||
|
||||
@ -110,6 +110,15 @@ services:
|
||||
# GOOGLE_CLIENT_ID: google_client_id
|
||||
# GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
# GOOGLE_CALLBACK_URL: http://example.com/api/auth/google/callback
|
||||
|
||||
# -- OpenID (Optional) --
|
||||
# OPENID_AUTHORIZATION_URL:
|
||||
# OPENID_CALLBACK_URL: http://example.com/api/auth/openid/callback
|
||||
# OPENID_CLIENT_ID:
|
||||
# OPENID_CLIENT_SECRET:
|
||||
# OPENID_ISSUER:
|
||||
# OPENID_TOKEN_URL:
|
||||
# OPENID_USER_INFO_URL:
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.routers.app.rule=Host(`example.com`)
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
-- AlterEnum
|
||||
ALTER TYPE "Provider" ADD VALUE 'openid';
|
||||
@ -11,6 +11,7 @@ enum Provider {
|
||||
email
|
||||
github
|
||||
google
|
||||
openid
|
||||
}
|
||||
|
||||
enum Visibility {
|
||||
|
||||
Reference in New Issue
Block a user