mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: resolved csrf for oauth2 using state parameter
This commit is contained in:
@@ -59,7 +59,7 @@ export default {
|
|||||||
const hsmModule = initializeHsmModule();
|
const hsmModule = initializeHsmModule();
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
const server = await main({ db, smtp, logger, queue, keyStore, hsmModule: hsmModule.getModule() });
|
const server = await main({ db, smtp, logger, queue, keyStore, hsmModule: hsmModule.getModule(), redis });
|
||||||
|
|
||||||
// @ts-expect-error type
|
// @ts-expect-error type
|
||||||
globalThis.testServer = server;
|
globalThis.testServer = server;
|
||||||
|
|||||||
7
backend/src/@types/fastify.d.ts
vendored
7
backend/src/@types/fastify.d.ts
vendored
@@ -1,5 +1,7 @@
|
|||||||
import "fastify";
|
import "fastify";
|
||||||
|
|
||||||
|
import { Redis } from "ioredis";
|
||||||
|
|
||||||
import { TUsers } from "@app/db/schemas";
|
import { TUsers } from "@app/db/schemas";
|
||||||
import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
|
import { TAccessApprovalPolicyServiceFactory } from "@app/ee/services/access-approval-policy/access-approval-policy-service";
|
||||||
import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service";
|
import { TAccessApprovalRequestServiceFactory } from "@app/ee/services/access-approval-request/access-approval-request-service";
|
||||||
@@ -87,6 +89,10 @@ import { TWebhookServiceFactory } from "@app/services/webhook/webhook-service";
|
|||||||
import { TWorkflowIntegrationServiceFactory } from "@app/services/workflow-integration/workflow-integration-service";
|
import { TWorkflowIntegrationServiceFactory } from "@app/services/workflow-integration/workflow-integration-service";
|
||||||
|
|
||||||
declare module "fastify" {
|
declare module "fastify" {
|
||||||
|
interface Session {
|
||||||
|
callbackPort: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface FastifyRequest {
|
interface FastifyRequest {
|
||||||
realIp: string;
|
realIp: string;
|
||||||
// used for mfa session authentication
|
// used for mfa session authentication
|
||||||
@@ -115,6 +121,7 @@ declare module "fastify" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FastifyInstance {
|
interface FastifyInstance {
|
||||||
|
redis: Redis;
|
||||||
services: {
|
services: {
|
||||||
login: TAuthLoginFactory;
|
login: TAuthLoginFactory;
|
||||||
password: TAuthPasswordFactory;
|
password: TAuthPasswordFactory;
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import { Authenticator, Strategy } from "@fastify/passport";
|
import { Authenticator, Strategy } from "@fastify/passport";
|
||||||
import fastifySession from "@fastify/session";
|
import fastifySession from "@fastify/session";
|
||||||
import RedisStore from "connect-redis";
|
import RedisStore from "connect-redis";
|
||||||
import { Redis } from "ioredis";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { OidcConfigsSchema } from "@app/db/schemas/oidc-configs";
|
import { OidcConfigsSchema } from "@app/db/schemas/oidc-configs";
|
||||||
@@ -21,7 +20,6 @@ import { AuthMode } from "@app/services/auth/auth-type";
|
|||||||
|
|
||||||
export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const redis = new Redis(appCfg.REDIS_URL);
|
|
||||||
const passport = new Authenticator({ key: "oidc", userProperty: "passportUser" });
|
const passport = new Authenticator({ key: "oidc", userProperty: "passportUser" });
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -30,7 +28,7 @@ export const registerOidcRouter = async (server: FastifyZodProvider) => {
|
|||||||
- Fastify session <> Redis structure is based on the ff: https://github.com/fastify/session/blob/master/examples/redis.js
|
- Fastify session <> Redis structure is based on the ff: https://github.com/fastify/session/blob/master/examples/redis.js
|
||||||
*/
|
*/
|
||||||
const redisStore = new RedisStore({
|
const redisStore = new RedisStore({
|
||||||
client: redis,
|
client: server.redis,
|
||||||
prefix: "oidc-session:",
|
prefix: "oidc-session:",
|
||||||
ttl: 600 // 10 minutes
|
ttl: 600 // 10 minutes
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import "./lib/telemetry/instrumentation";
|
import "./lib/telemetry/instrumentation";
|
||||||
|
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
|
import { Redis } from "ioredis";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
import { initializeHsmModule } from "@app/ee/services/hsm/hsm-fns";
|
||||||
@@ -57,11 +58,12 @@ const run = async () => {
|
|||||||
const smtp = smtpServiceFactory(formatSmtpConfig());
|
const smtp = smtpServiceFactory(formatSmtpConfig());
|
||||||
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
const queue = queueServiceFactory(appCfg.REDIS_URL);
|
||||||
const keyStore = keyStoreFactory(appCfg.REDIS_URL);
|
const keyStore = keyStoreFactory(appCfg.REDIS_URL);
|
||||||
|
const redis = new Redis(appCfg.REDIS_URL);
|
||||||
|
|
||||||
const hsmModule = initializeHsmModule();
|
const hsmModule = initializeHsmModule();
|
||||||
hsmModule.initialize();
|
hsmModule.initialize();
|
||||||
|
|
||||||
const server = await main({ db, auditLogDb, hsmModule: hsmModule.getModule(), smtp, logger, queue, keyStore });
|
const server = await main({ db, auditLogDb, hsmModule: hsmModule.getModule(), smtp, logger, queue, keyStore, redis });
|
||||||
const bootstrap = await bootstrapCheck({ db });
|
const bootstrap = await bootstrapCheck({ db });
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import helmet from "@fastify/helmet";
|
|||||||
import type { FastifyRateLimitOptions } from "@fastify/rate-limit";
|
import type { FastifyRateLimitOptions } from "@fastify/rate-limit";
|
||||||
import ratelimiter from "@fastify/rate-limit";
|
import ratelimiter from "@fastify/rate-limit";
|
||||||
import fastify from "fastify";
|
import fastify from "fastify";
|
||||||
|
import { Redis } from "ioredis";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
import { Logger } from "pino";
|
import { Logger } from "pino";
|
||||||
|
|
||||||
@@ -39,10 +40,11 @@ type TMain = {
|
|||||||
queue: TQueueServiceFactory;
|
queue: TQueueServiceFactory;
|
||||||
keyStore: TKeyStoreFactory;
|
keyStore: TKeyStoreFactory;
|
||||||
hsmModule: HsmModule;
|
hsmModule: HsmModule;
|
||||||
|
redis: Redis;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Run the server!
|
// Run the server!
|
||||||
export const main = async ({ db, hsmModule, auditLogDb, smtp, logger, queue, keyStore }: TMain) => {
|
export const main = async ({ db, hsmModule, auditLogDb, smtp, logger, queue, keyStore, redis }: TMain) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const server = fastify({
|
const server = fastify({
|
||||||
@@ -56,6 +58,7 @@ export const main = async ({ db, hsmModule, auditLogDb, smtp, logger, queue, key
|
|||||||
server.setValidatorCompiler(validatorCompiler);
|
server.setValidatorCompiler(validatorCompiler);
|
||||||
server.setSerializerCompiler(serializerCompiler);
|
server.setSerializerCompiler(serializerCompiler);
|
||||||
|
|
||||||
|
server.decorate("redis", redis);
|
||||||
server.addContentTypeParser("application/scim+json", { parseAs: "string" }, (_, body, done) => {
|
server.addContentTypeParser("application/scim+json", { parseAs: "string" }, (_, body, done) => {
|
||||||
try {
|
try {
|
||||||
const strBody = body instanceof Buffer ? body.toString() : body;
|
const strBody = body instanceof Buffer ? body.toString() : body;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import { Authenticator } from "@fastify/passport";
|
import { Authenticator } from "@fastify/passport";
|
||||||
import fastifySession from "@fastify/session";
|
import fastifySession from "@fastify/session";
|
||||||
|
import RedisStore from "connect-redis";
|
||||||
import { Strategy as GitHubStrategy } from "passport-github";
|
import { Strategy as GitHubStrategy } from "passport-github";
|
||||||
import { Strategy as GitLabStrategy } from "passport-gitlab2";
|
import { Strategy as GitLabStrategy } from "passport-gitlab2";
|
||||||
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
|
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
|
||||||
@@ -21,8 +22,22 @@ import { AuthMethod } from "@app/services/auth/auth-type";
|
|||||||
|
|
||||||
export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const passport = new Authenticator({ key: "sso", userProperty: "passportUser" });
|
const passport = new Authenticator({ key: "sso", userProperty: "passportUser" });
|
||||||
await server.register(fastifySession, { secret: appCfg.COOKIE_SECRET_SIGN_KEY });
|
const redisStore = new RedisStore({
|
||||||
|
client: server.redis,
|
||||||
|
prefix: "oauth-session:",
|
||||||
|
ttl: 600 // 10 minutes
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.register(fastifySession, {
|
||||||
|
secret: appCfg.COOKIE_SECRET_SIGN_KEY,
|
||||||
|
store: redisStore,
|
||||||
|
cookie: {
|
||||||
|
secure: appCfg.HTTPS_ENABLED,
|
||||||
|
sameSite: "lax" // we want cookies to be sent to Infisical in redirects originating from IDP server
|
||||||
|
}
|
||||||
|
});
|
||||||
await server.register(passport.initialize());
|
await server.register(passport.initialize());
|
||||||
await server.register(passport.secureSession());
|
await server.register(passport.secureSession());
|
||||||
// passport oauth strategy for Google
|
// passport oauth strategy for Google
|
||||||
@@ -35,11 +50,15 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
clientID: appCfg.CLIENT_ID_GOOGLE_LOGIN as string,
|
clientID: appCfg.CLIENT_ID_GOOGLE_LOGIN as string,
|
||||||
clientSecret: appCfg.CLIENT_SECRET_GOOGLE_LOGIN as string,
|
clientSecret: appCfg.CLIENT_SECRET_GOOGLE_LOGIN as string,
|
||||||
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/google`,
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/google`,
|
||||||
scope: ["profile", " email"]
|
scope: ["profile", " email"],
|
||||||
|
state: true
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
async (req, _accessToken, _refreshToken, profile, cb) => {
|
async (req, _accessToken, _refreshToken, profile, cb) => {
|
||||||
try {
|
try {
|
||||||
|
// @ts-expect-error this is because this is express type and not fastify
|
||||||
|
const callbackPort = req.session.get("callbackPort");
|
||||||
|
|
||||||
const email = profile?.emails?.[0]?.value;
|
const email = profile?.emails?.[0]?.value;
|
||||||
if (!email)
|
if (!email)
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -52,7 +71,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
firstName: profile?.name?.givenName || "",
|
firstName: profile?.name?.givenName || "",
|
||||||
lastName: profile?.name?.familyName || "",
|
lastName: profile?.name?.familyName || "",
|
||||||
authMethod: AuthMethod.GOOGLE,
|
authMethod: AuthMethod.GOOGLE,
|
||||||
callbackPort: req.query.state as string
|
callbackPort
|
||||||
});
|
});
|
||||||
cb(null, { isUserCompleted, providerAuthToken });
|
cb(null, { isUserCompleted, providerAuthToken });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -74,10 +93,14 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
clientID: appCfg.CLIENT_ID_GITHUB_LOGIN as string,
|
clientID: appCfg.CLIENT_ID_GITHUB_LOGIN as string,
|
||||||
clientSecret: appCfg.CLIENT_SECRET_GITHUB_LOGIN as string,
|
clientSecret: appCfg.CLIENT_SECRET_GITHUB_LOGIN as string,
|
||||||
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`,
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/github`,
|
||||||
scope: ["user:email"]
|
scope: ["user:email"],
|
||||||
|
// akhilmhdh: because the ts type for this is outdated by the maintainer
|
||||||
|
state: true as unknown as string
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
async (req, accessToken, _refreshToken, profile, cb) => {
|
async (req, accessToken, _refreshToken, profile, cb) => {
|
||||||
|
// @ts-expect-error this is because this is express type and not fastify
|
||||||
|
const callbackPort = req.session.get("callbackPort");
|
||||||
try {
|
try {
|
||||||
const ghEmails = await fetchGithubEmails(accessToken);
|
const ghEmails = await fetchGithubEmails(accessToken);
|
||||||
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
const { email } = ghEmails.filter((gitHubEmail) => gitHubEmail.primary)[0];
|
||||||
@@ -86,7 +109,7 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
firstName: profile.displayName,
|
firstName: profile.displayName,
|
||||||
lastName: "",
|
lastName: "",
|
||||||
authMethod: AuthMethod.GITHUB,
|
authMethod: AuthMethod.GITHUB,
|
||||||
callbackPort: req.query.state as string
|
callbackPort
|
||||||
});
|
});
|
||||||
return cb(null, { isUserCompleted, providerAuthToken });
|
return cb(null, { isUserCompleted, providerAuthToken });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -110,17 +133,20 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
clientID: appCfg.CLIENT_ID_GITLAB_LOGIN,
|
clientID: appCfg.CLIENT_ID_GITLAB_LOGIN,
|
||||||
clientSecret: appCfg.CLIENT_SECRET_GITLAB_LOGIN,
|
clientSecret: appCfg.CLIENT_SECRET_GITLAB_LOGIN,
|
||||||
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/gitlab`,
|
callbackURL: `${appCfg.SITE_URL}/api/v1/sso/gitlab`,
|
||||||
baseURL: appCfg.CLIENT_GITLAB_LOGIN_URL
|
baseURL: appCfg.CLIENT_GITLAB_LOGIN_URL,
|
||||||
|
state: true
|
||||||
},
|
},
|
||||||
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
async (req: any, _accessToken: string, _refreshToken: string, profile: any, cb: any) => {
|
||||||
try {
|
try {
|
||||||
|
const callbackPort = req.session.get("callbackPort");
|
||||||
|
|
||||||
const email = profile.emails[0].value;
|
const email = profile.emails[0].value;
|
||||||
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
const { isUserCompleted, providerAuthToken } = await server.services.login.oauth2Login({
|
||||||
email,
|
email,
|
||||||
firstName: profile.displayName,
|
firstName: profile.displayName,
|
||||||
lastName: "",
|
lastName: "",
|
||||||
authMethod: AuthMethod.GITLAB,
|
authMethod: AuthMethod.GITLAB,
|
||||||
callbackPort: req.query.state as string
|
callbackPort
|
||||||
});
|
});
|
||||||
|
|
||||||
return cb(null, { isUserCompleted, providerAuthToken });
|
return cb(null, { isUserCompleted, providerAuthToken });
|
||||||
@@ -141,17 +167,24 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
callback_port: z.string().optional()
|
callback_port: z.string().optional()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
preValidation: (req, res) =>
|
preValidation: [
|
||||||
(
|
async (req, res) => {
|
||||||
passport.authenticate("google", {
|
const { callback_port: callbackPort } = req.query;
|
||||||
scope: ["profile", "email"],
|
// ensure fresh session state per login attempt
|
||||||
session: false,
|
await req.session.regenerate();
|
||||||
state: req.query.callback_port,
|
if (callbackPort) {
|
||||||
authInfo: false
|
req.session.set("callbackPort", callbackPort);
|
||||||
// this is due to zod type difference
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
return (
|
||||||
}) as any
|
passport.authenticate("google", {
|
||||||
)(req, res),
|
scope: ["profile", "email"],
|
||||||
|
authInfo: false
|
||||||
|
// this is due to zod type difference
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
}) as any
|
||||||
|
)(req, res);
|
||||||
|
}
|
||||||
|
],
|
||||||
handler: () => {}
|
handler: () => {}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -164,7 +197,8 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
authInfo: false
|
authInfo: false
|
||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
}) as never,
|
}) as never,
|
||||||
handler: (req, res) => {
|
handler: async (req, res) => {
|
||||||
|
await req.session.destroy();
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
@@ -184,15 +218,24 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
callback_port: z.string().optional()
|
callback_port: z.string().optional()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
preValidation: (req, res) =>
|
preValidation: [
|
||||||
(
|
async (req, res) => {
|
||||||
passport.authenticate("github", {
|
const { callback_port: callbackPort } = req.query;
|
||||||
session: false,
|
// ensure fresh session state per login attempt
|
||||||
state: req.query.callback_port,
|
await req.session.regenerate();
|
||||||
authInfo: false
|
if (callbackPort) {
|
||||||
// this is due to zod type difference
|
req.session.set("callbackPort", callbackPort);
|
||||||
}) as any
|
}
|
||||||
)(req, res),
|
|
||||||
|
return (
|
||||||
|
passport.authenticate("github", {
|
||||||
|
session: false,
|
||||||
|
authInfo: false
|
||||||
|
// this is due to zod type difference
|
||||||
|
}) as any
|
||||||
|
)(req, res);
|
||||||
|
}
|
||||||
|
],
|
||||||
handler: () => {}
|
handler: () => {}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -205,7 +248,8 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
authInfo: false
|
authInfo: false
|
||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
}) as any,
|
}) as any,
|
||||||
handler: (req, res) => {
|
handler: async (req, res) => {
|
||||||
|
await req.session.destroy();
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
@@ -225,16 +269,25 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
callback_port: z.string().optional()
|
callback_port: z.string().optional()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
preValidation: (req, res) =>
|
preValidation: [
|
||||||
(
|
async (req, res) => {
|
||||||
passport.authenticate("gitlab", {
|
const { callback_port: callbackPort } = req.query;
|
||||||
session: false,
|
// ensure fresh session state per login attempt
|
||||||
state: req.query.callback_port,
|
await req.session.regenerate();
|
||||||
authInfo: false
|
if (callbackPort) {
|
||||||
// this is due to zod type difference
|
req.session.set("callbackPort", callbackPort);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
}
|
||||||
}) as any
|
|
||||||
)(req, res),
|
return (
|
||||||
|
passport.authenticate("gitlab", {
|
||||||
|
session: false,
|
||||||
|
authInfo: false
|
||||||
|
// this is due to zod type difference
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
}) as any
|
||||||
|
)(req, res);
|
||||||
|
}
|
||||||
|
],
|
||||||
handler: () => {}
|
handler: () => {}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -248,7 +301,8 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => {
|
|||||||
// this is due to zod type difference
|
// this is due to zod type difference
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
}) as any,
|
}) as any,
|
||||||
handler: (req, res) => {
|
handler: async (req, res) => {
|
||||||
|
await req.session.destroy();
|
||||||
if (req.passportUser.isUserCompleted) {
|
if (req.passportUser.isUserCompleted) {
|
||||||
return res.redirect(
|
return res.redirect(
|
||||||
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
`${appCfg.SITE_URL}/login/sso?token=${encodeURIComponent(req.passportUser.providerAuthToken)}`
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>Join your organization on Infisical</h2>
|
<h2>Join your organization on Infisical</h2>
|
||||||
<p>{{inviterFirstName}} ({{inviterUsername}}) has invited you to their Infisical organization — {{organizationName}}</p>
|
<p>{{inviterFirstName}} ({{inviterUsername}}) has invited you to their Infisical organization named {{organizationName}}</p>
|
||||||
<a href="{{callback_url}}?token={{token}}{{#if metadata}}&metadata={{metadata}}{{/if}}&to={{email}}&organization_id={{organizationId}}">Join now</a>
|
<a href="{{callback_url}}?token={{token}}{{#if metadata}}&metadata={{metadata}}{{/if}}&to={{email}}&organization_id={{organizationId}}">Click to join</a>
|
||||||
<h3>What is Infisical?</h3>
|
<h3>What is Infisical?</h3>
|
||||||
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.</p>
|
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets and configs.</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h2>Join your team on Infisical</h2>
|
<h2>Join your team on Infisical</h2>
|
||||||
<p>You have been invited to a new Infisical project — {{workspaceName}}</p>
|
<p>You have been invited to a new Infisical project named {{workspaceName}}</p>
|
||||||
<a href="{{callback_url}}">Join now</a>
|
<a href="{{callback_url}}">Click to join</a>
|
||||||
<h3>What is Infisical?</h3>
|
<h3>What is Infisical?</h3>
|
||||||
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets
|
<p>Infisical is an easy-to-use end-to-end encrypted tool that enables developers to sync and manage their secrets
|
||||||
and configs.</p>
|
and configs.</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user