mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 06:26:16 +00:00
Update JWT secret scheme, replace many secrets with one secret
This commit is contained in:
+10
-16
@@ -5,20 +5,7 @@ ENCRYPTION_KEY=6c1fe4e407b8911c104518103505b218
|
|||||||
|
|
||||||
# JWT
|
# JWT
|
||||||
# Required secrets to sign JWT tokens
|
# Required secrets to sign JWT tokens
|
||||||
JWT_SIGNUP_SECRET=3679e04ca949f914c03332aaaeba805a
|
AUTH_SECRET=5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE=
|
||||||
JWT_REFRESH_SECRET=5f2f3c8f0159068dc2bbb3a652a716ff
|
|
||||||
JWT_AUTH_SECRET=4be6ba5602e0fa0ac6ac05c3cd4d247f
|
|
||||||
JWT_SERVICE_SECRET=f32f716d70a42c5703f4656015e76200
|
|
||||||
JWT_SERVICE_TOKEN_SECRET=f32f716d70a42c5703f4656015e76200
|
|
||||||
JWT_PROVIDER_AUTH_SECRET=f32f716d70a42c5703f4656015e76201
|
|
||||||
|
|
||||||
# JWT lifetime
|
|
||||||
# Optional lifetimes for JWT tokens expressed in seconds or a string
|
|
||||||
# describing a time span (e.g. 60, "2 days", "10h", "7d")
|
|
||||||
JWT_AUTH_LIFETIME=
|
|
||||||
JWT_REFRESH_LIFETIME=
|
|
||||||
JWT_SIGNUP_LIFETIME=
|
|
||||||
JWT_PROVIDER_AUTH_LIFETIME=
|
|
||||||
|
|
||||||
# MongoDB
|
# MongoDB
|
||||||
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref
|
# Backend will connect to the MongoDB instance at connection string MONGO_URL which can either be a ref
|
||||||
@@ -68,5 +55,12 @@ SENTRY_DSN=
|
|||||||
POSTHOG_HOST=
|
POSTHOG_HOST=
|
||||||
POSTHOG_PROJECT_API_KEY=
|
POSTHOG_PROJECT_API_KEY=
|
||||||
|
|
||||||
CLIENT_ID_GOOGLE=
|
# SSO-specific variables
|
||||||
CLIENT_SECRET_GOOGLE=
|
CLIENT_ID_GOOGLE_LOGIN=
|
||||||
|
CLIENT_SECRET_GOOGLE_LOGIN=
|
||||||
|
|
||||||
|
CLIENT_ID_GITHUB_LOGIN=
|
||||||
|
CLIENT_SECRET_GITHUB_LOGIN=
|
||||||
|
|
||||||
|
CLIENT_ID_GITLAB_LOGIN=
|
||||||
|
CLIENT_SECRET_GITLAB_LOGIN=
|
||||||
|
|||||||
@@ -17,17 +17,13 @@ export const getRootEncryptionKey = async () => {
|
|||||||
}
|
}
|
||||||
export const getInviteOnlySignup = async () => (await client.getSecret("INVITE_ONLY_SIGNUP")).secretValue === "true"
|
export const getInviteOnlySignup = async () => (await client.getSecret("INVITE_ONLY_SIGNUP")).secretValue === "true"
|
||||||
export const getSaltRounds = async () => parseInt((await client.getSecret("SALT_ROUNDS")).secretValue) || 10;
|
export const getSaltRounds = async () => parseInt((await client.getSecret("SALT_ROUNDS")).secretValue) || 10;
|
||||||
|
export const getAuthSecret = async () => (await client.getSecret("AUTH_SECRET")).secretValue; // new
|
||||||
export const getJwtAuthLifetime = async () => (await client.getSecret("JWT_AUTH_LIFETIME")).secretValue || "10d";
|
export const getJwtAuthLifetime = async () => (await client.getSecret("JWT_AUTH_LIFETIME")).secretValue || "10d";
|
||||||
export const getJwtAuthSecret = async () => (await client.getSecret("JWT_AUTH_SECRET")).secretValue;
|
|
||||||
export const getJwtMfaLifetime = async () => (await client.getSecret("JWT_MFA_LIFETIME")).secretValue || "5m";
|
export const getJwtMfaLifetime = async () => (await client.getSecret("JWT_MFA_LIFETIME")).secretValue || "5m";
|
||||||
export const getJwtMfaSecret = async () => (await client.getSecret("JWT_MFA_LIFETIME")).secretValue || "5m";
|
|
||||||
export const getJwtRefreshLifetime = async () => (await client.getSecret("JWT_REFRESH_LIFETIME")).secretValue || "90d";
|
export const getJwtRefreshLifetime = async () => (await client.getSecret("JWT_REFRESH_LIFETIME")).secretValue || "90d";
|
||||||
export const getJwtRefreshSecret = async () => (await client.getSecret("JWT_REFRESH_SECRET")).secretValue;
|
export const getJwtServiceSecret = async () => (await client.getSecret("JWT_SERVICE_SECRET")).secretValue; // TODO: deprecate (related to ST V1)
|
||||||
export const getJwtServiceSecret = async () => (await client.getSecret("JWT_SERVICE_SECRET")).secretValue;
|
|
||||||
export const getJwtSignupLifetime = async () => (await client.getSecret("JWT_SIGNUP_LIFETIME")).secretValue || "15m";
|
export const getJwtSignupLifetime = async () => (await client.getSecret("JWT_SIGNUP_LIFETIME")).secretValue || "15m";
|
||||||
export const getJwtProviderAuthSecret = async () => (await client.getSecret("JWT_PROVIDER_AUTH_SECRET")).secretValue;
|
|
||||||
export const getJwtProviderAuthLifetime = async () => (await client.getSecret("JWT_PROVIDER_AUTH_LIFETIME")).secretValue || "15m";
|
export const getJwtProviderAuthLifetime = async () => (await client.getSecret("JWT_PROVIDER_AUTH_LIFETIME")).secretValue || "15m";
|
||||||
export const getJwtSignupSecret = async () => (await client.getSecret("JWT_SIGNUP_SECRET")).secretValue;
|
|
||||||
export const getJwtServiceTokenSecret = async () => (await client.getSecret("JWT_SERVICE_TOKEN_SECRET")).secretValue;
|
export const getJwtServiceTokenSecret = async () => (await client.getSecret("JWT_SERVICE_TOKEN_SECRET")).secretValue;
|
||||||
export const getMongoURL = async () => (await client.getSecret("MONGO_URL")).secretValue;
|
export const getMongoURL = async () => (await client.getSecret("MONGO_URL")).secretValue;
|
||||||
export const getNodeEnv = async () => (await client.getSecret("NODE_ENV")).secretValue || "production";
|
export const getNodeEnv = async () => (await client.getSecret("NODE_ENV")).secretValue || "production";
|
||||||
|
|||||||
@@ -6,15 +6,18 @@ const jsrp = require("jsrp");
|
|||||||
import { LoginSRPDetail, TokenVersion, User } from "../../models";
|
import { LoginSRPDetail, TokenVersion, User } from "../../models";
|
||||||
import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth";
|
import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth";
|
||||||
import { checkUserDevice } from "../../helpers/user";
|
import { checkUserDevice } from "../../helpers/user";
|
||||||
import { ACTION_LOGIN, ACTION_LOGOUT } from "../../variables";
|
import {
|
||||||
|
ACTION_LOGIN,
|
||||||
|
ACTION_LOGOUT,
|
||||||
|
AuthTokenType
|
||||||
|
} from "../../variables";
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import { EELogService } from "../../ee/services";
|
import { EELogService } from "../../ee/services";
|
||||||
import { getUserAgentType } from "../../utils/posthog";
|
import { getUserAgentType } from "../../utils/posthog";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getHttpsEnabled,
|
getHttpsEnabled,
|
||||||
getJwtAuthLifetime,
|
getJwtAuthLifetime
|
||||||
getJwtAuthSecret,
|
|
||||||
getJwtRefreshSecret
|
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { ActorType } from "../../ee/models";
|
import { ActorType } from "../../ee/models";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
@@ -238,6 +241,7 @@ export const checkAuth = async (req: Request, res: Response) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const getNewToken = async (req: Request, res: Response) => {
|
export const getNewToken = async (req: Request, res: Response) => {
|
||||||
|
|
||||||
const refreshToken = req.cookies.jid;
|
const refreshToken = req.cookies.jid;
|
||||||
|
|
||||||
if (!refreshToken)
|
if (!refreshToken)
|
||||||
@@ -245,7 +249,9 @@ export const getNewToken = async (req: Request, res: Response) => {
|
|||||||
message: "Failed to find refresh token in request cookies"
|
message: "Failed to find refresh token in request cookies"
|
||||||
});
|
});
|
||||||
|
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>jwt.verify(refreshToken, await getJwtRefreshSecret());
|
const decodedToken = <jwt.UserIDJwtPayload>jwt.verify(refreshToken, await getAuthSecret());
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId
|
_id: decodedToken.userId
|
||||||
@@ -268,12 +274,13 @@ export const getNewToken = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
userId: decodedToken.userId,
|
userId: decodedToken.userId,
|
||||||
tokenVersionId: tokenVersion._id.toString(),
|
tokenVersionId: tokenVersion._id.toString(),
|
||||||
accessVersion: tokenVersion.refreshVersion
|
accessVersion: tokenVersion.refreshVersion
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtAuthLifetime(),
|
expiresIn: await getJwtAuthLifetime(),
|
||||||
secret: await getJwtAuthSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import { updateSubscriptionOrgQuantity } from "../../helpers/organization";
|
|||||||
import { sendMail } from "../../helpers/nodemailer";
|
import { sendMail } from "../../helpers/nodemailer";
|
||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { EELicenseService } from "../../ee/services";
|
import { EELicenseService } from "../../ee/services";
|
||||||
import { ACCEPTED, INVITED, MEMBER, TOKEN_EMAIL_ORG_INVITATION } from "../../variables";
|
import { ACCEPTED, AuthTokenType, INVITED, MEMBER, TOKEN_EMAIL_ORG_INVITATION } from "../../variables";
|
||||||
import * as reqValidator from "../../validation/membershipOrg";
|
import * as reqValidator from "../../validation/membershipOrg";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getJwtSignupLifetime,
|
getJwtSignupLifetime,
|
||||||
getJwtSignupSecret,
|
|
||||||
getSiteURL,
|
getSiteURL,
|
||||||
getSmtpConfigured
|
getSmtpConfigured
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
@@ -272,10 +272,11 @@ export const verifyUserToOrganization = async (req: Request, res: Response) => {
|
|||||||
// generate temporary signup token
|
// generate temporary signup token
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.SIGNUP_TOKEN,
|
||||||
userId: user._id.toString()
|
userId: user._id.toString()
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtSignupLifetime(),
|
expiresIn: await getJwtSignupLifetime(),
|
||||||
secret: await getJwtSignupSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import * as bigintConversion from "bigint-conversion";
|
|||||||
import { BackupPrivateKey, LoginSRPDetail, User } from "../../models";
|
import { BackupPrivateKey, LoginSRPDetail, User } from "../../models";
|
||||||
import { clearTokens, createToken, sendMail } from "../../helpers";
|
import { clearTokens, createToken, sendMail } from "../../helpers";
|
||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { TOKEN_EMAIL_PASSWORD_RESET } from "../../variables";
|
import { AuthTokenType, TOKEN_EMAIL_PASSWORD_RESET } from "../../variables";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { BadRequestError } from "../../utils/errors";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getHttpsEnabled,
|
getHttpsEnabled,
|
||||||
getJwtSignupLifetime,
|
getJwtSignupLifetime,
|
||||||
getJwtSignupSecret,
|
|
||||||
getSiteURL
|
getSiteURL
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { ActorType } from "../../ee/models";
|
import { ActorType } from "../../ee/models";
|
||||||
@@ -88,10 +88,11 @@ export const emailPasswordResetVerify = async (req: Request, res: Response) => {
|
|||||||
// generate temporary password-reset token
|
// generate temporary password-reset token
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.SIGNUP_TOKEN,
|
||||||
userId: user._id.toString()
|
userId: user._id.toString()
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtSignupLifetime(),
|
expiresIn: await getJwtSignupLifetime(),
|
||||||
secret: await getJwtSignupSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import { checkEmailVerification, sendEmailVerification } from "../../helpers/sig
|
|||||||
import { createToken } from "../../helpers/auth";
|
import { createToken } from "../../helpers/auth";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { BadRequestError } from "../../utils/errors";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getInviteOnlySignup,
|
getInviteOnlySignup,
|
||||||
getJwtSignupLifetime,
|
getJwtSignupLifetime,
|
||||||
getJwtSignupSecret,
|
|
||||||
getSmtpConfigured
|
getSmtpConfigured
|
||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { validateUserEmail } from "../../validation";
|
import { validateUserEmail } from "../../validation";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/auth";
|
import * as reqValidator from "../../validation/auth";
|
||||||
|
import { AuthTokenType } from "../../variables";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signup step 1: Initialize account for user under email [email] and send a verification code
|
* Signup step 1: Initialize account for user under email [email] and send a verification code
|
||||||
@@ -95,10 +96,11 @@ export const verifyEmailSignup = async (req: Request, res: Response) => {
|
|||||||
// generate temporary signup token
|
// generate temporary signup token
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.SIGNUP_TOKEN,
|
||||||
userId: user._id.toString()
|
userId: user._id.toString()
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtSignupLifetime(),
|
expiresIn: await getJwtSignupLifetime(),
|
||||||
secret: await getJwtSignupSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import { sendMail } from "../../helpers/nodemailer";
|
|||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { EELogService } from "../../ee/services";
|
import { EELogService } from "../../ee/services";
|
||||||
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
||||||
import { ACTION_LOGIN, TOKEN_EMAIL_MFA } from "../../variables";
|
import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
||||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
||||||
import { getHttpsEnabled, getJwtMfaLifetime, getJwtMfaSecret } from "../../config";
|
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/auth";
|
import * as reqValidator from "../../validation/auth";
|
||||||
|
|
||||||
@@ -109,10 +109,11 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
// generate temporary MFA token
|
// generate temporary MFA token
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.MFA_TOKEN,
|
||||||
userId: user._id.toString()
|
userId: user._id.toString()
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtMfaLifetime(),
|
expiresIn: await getJwtMfaLifetime(),
|
||||||
secret: await getJwtMfaSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
const code = await TokenService.createToken({
|
const code = await TokenService.createToken({
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import { sendMail } from "../../helpers/nodemailer";
|
|||||||
import { TokenService } from "../../services";
|
import { TokenService } from "../../services";
|
||||||
import { EELogService } from "../../ee/services";
|
import { EELogService } from "../../ee/services";
|
||||||
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
import { BadRequestError, InternalServerError } from "../../utils/errors";
|
||||||
import { ACTION_LOGIN, TOKEN_EMAIL_MFA } from "../../variables";
|
import { ACTION_LOGIN, AuthTokenType, TOKEN_EMAIL_MFA } from "../../variables";
|
||||||
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
import { getUserAgentType } from "../../utils/posthog"; // TODO: move this
|
||||||
import { getHttpsEnabled, getJwtMfaLifetime, getJwtMfaSecret } from "../../config";
|
import { getAuthSecret, getHttpsEnabled, getJwtMfaLifetime } from "../../config";
|
||||||
import { AuthMethod } from "../../models/user";
|
import { AuthMethod } from "../../models/user";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
import * as reqValidator from "../../validation/auth";
|
import * as reqValidator from "../../validation/auth";
|
||||||
@@ -134,10 +134,11 @@ export const login2 = async (req: Request, res: Response) => {
|
|||||||
// generate temporary MFA token
|
// generate temporary MFA token
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.MFA_TOKEN,
|
||||||
userId: user._id.toString()
|
userId: user._id.toString()
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtMfaLifetime(),
|
expiresIn: await getJwtMfaLifetime(),
|
||||||
secret: await getJwtMfaSecret()
|
secret: await getAuthSecret()
|
||||||
});
|
});
|
||||||
|
|
||||||
const code = await TokenService.createToken({
|
const code = await TokenService.createToken({
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import { MembershipOrg, User } from "../../models";
|
|||||||
import { completeAccount } from "../../helpers/user";
|
import { completeAccount } from "../../helpers/user";
|
||||||
import { initializeDefaultOrg } from "../../helpers/signup";
|
import { initializeDefaultOrg } from "../../helpers/signup";
|
||||||
import { issueAuthTokens, validateProviderAuthToken } from "../../helpers/auth";
|
import { issueAuthTokens, validateProviderAuthToken } from "../../helpers/auth";
|
||||||
import { ACCEPTED, INVITED } from "../../variables";
|
import { ACCEPTED, AuthTokenType, INVITED } from "../../variables";
|
||||||
import { standardRequest } from "../../config/request";
|
import { standardRequest } from "../../config/request";
|
||||||
import { getHttpsEnabled, getJwtSignupSecret, getLoopsApiKey } from "../../config";
|
import { getAuthSecret, getHttpsEnabled, getLoopsApiKey } from "../../config";
|
||||||
import { BadRequestError } from "../../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
|
||||||
import { TelemetryService } from "../../services";
|
import { TelemetryService } from "../../services";
|
||||||
import { AuthMethod } from "../../models";
|
import { AuthMethod } from "../../models";
|
||||||
import { validateRequest } from "../../helpers/validation";
|
import { validateRequest } from "../../helpers/validation";
|
||||||
@@ -78,12 +78,11 @@ export const completeAccountSignup = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
jwt.verify(AUTH_TOKEN_VALUE, await getJwtSignupSecret())
|
jwt.verify(AUTH_TOKEN_VALUE, await getAuthSecret())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (decodedToken.userId !== user.id) {
|
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw UnauthorizedRequestError();
|
||||||
throw BadRequestError();
|
if (decodedToken.userId !== user.id) throw UnauthorizedRequestError();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// complete setting up user's account
|
// complete setting up user's account
|
||||||
|
|||||||
+15
-16
@@ -19,15 +19,14 @@ import {
|
|||||||
UnauthorizedRequestError,
|
UnauthorizedRequestError,
|
||||||
} from "../utils/errors";
|
} from "../utils/errors";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getJwtAuthLifetime,
|
getJwtAuthLifetime,
|
||||||
getJwtAuthSecret,
|
|
||||||
getJwtProviderAuthSecret,
|
|
||||||
getJwtRefreshLifetime,
|
getJwtRefreshLifetime,
|
||||||
getJwtRefreshSecret,
|
|
||||||
getJwtServiceTokenSecret
|
getJwtServiceTokenSecret
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import {
|
import {
|
||||||
AuthMode
|
AuthMode,
|
||||||
|
AuthTokenType
|
||||||
} from "../variables";
|
} from "../variables";
|
||||||
import {
|
import {
|
||||||
ServiceTokenAuthData,
|
ServiceTokenAuthData,
|
||||||
@@ -51,8 +50,6 @@ export const validateAuthMode = ({
|
|||||||
acceptedAuthModes: AuthMode[]
|
acceptedAuthModes: AuthMode[]
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
// TODO: update this to accept service token v3
|
|
||||||
|
|
||||||
const apiKey = headers["x-api-key"];
|
const apiKey = headers["x-api-key"];
|
||||||
const authHeader = headers["authorization"];
|
const authHeader = headers["authorization"];
|
||||||
|
|
||||||
@@ -120,9 +117,11 @@ export const getAuthUserPayload = async ({
|
|||||||
authTokenValue: string;
|
authTokenValue: string;
|
||||||
}): Promise<UserAuthData> => {
|
}): Promise<UserAuthData> => {
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
jwt.verify(authTokenValue, await getJwtAuthSecret())
|
jwt.verify(authTokenValue, await getAuthSecret())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.ACCESS_TOKEN) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: new Types.ObjectId(decodedToken.userId),
|
_id: new Types.ObjectId(decodedToken.userId),
|
||||||
}).select("+publicKey +accessVersion");
|
}).select("+publicKey +accessVersion");
|
||||||
@@ -159,11 +158,6 @@ export const getAuthUserPayload = async ({
|
|||||||
userAgent: req.headers["user-agent"] ?? "",
|
userAgent: req.headers["user-agent"] ?? "",
|
||||||
userAgentType: getUserAgentType(req.headers["user-agent"])
|
userAgentType: getUserAgentType(req.headers["user-agent"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// return ({
|
|
||||||
// user,
|
|
||||||
// tokenVersionId: tokenVersion._id, // what to do with this? // move this out
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -404,22 +398,24 @@ export const issueAuthTokens = async ({
|
|||||||
// issue tokens
|
// issue tokens
|
||||||
const token = createToken({
|
const token = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
userId,
|
userId,
|
||||||
tokenVersionId: tokenVersion._id.toString(),
|
tokenVersionId: tokenVersion._id.toString(),
|
||||||
accessVersion: tokenVersion.accessVersion,
|
accessVersion: tokenVersion.accessVersion,
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtAuthLifetime(),
|
expiresIn: await getJwtAuthLifetime(),
|
||||||
secret: await getJwtAuthSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshToken = createToken({
|
const refreshToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.REFRESH_TOKEN,
|
||||||
userId,
|
userId,
|
||||||
tokenVersionId: tokenVersion._id.toString(),
|
tokenVersionId: tokenVersion._id.toString(),
|
||||||
refreshVersion: tokenVersion.refreshVersion,
|
refreshVersion: tokenVersion.refreshVersion,
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtRefreshLifetime(),
|
expiresIn: await getJwtRefreshLifetime(),
|
||||||
secret: await getJwtRefreshSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -451,7 +447,7 @@ export const clearTokens = async (tokenVersionId: Types.ObjectId): Promise<void>
|
|||||||
* bearer/auth, refresh, and temporary signup tokens
|
* bearer/auth, refresh, and temporary signup tokens
|
||||||
* @param {Object} obj
|
* @param {Object} obj
|
||||||
* @param {Object} obj.payload - payload of (JWT) token
|
* @param {Object} obj.payload - payload of (JWT) token
|
||||||
* @param {String} obj.secret - (JWT) secret such as [JWT_AUTH_SECRET]
|
* @param {String} obj.secret - (JWT) secret such as [AUTH_SECRET]
|
||||||
* @param {String} obj.expiresIn - string describing time span such as '10h' or '7d'
|
* @param {String} obj.expiresIn - string describing time span such as '10h' or '7d'
|
||||||
*/
|
*/
|
||||||
export const createToken = ({
|
export const createToken = ({
|
||||||
@@ -479,14 +475,17 @@ export const validateProviderAuthToken = async ({
|
|||||||
email: string;
|
email: string;
|
||||||
providerAuthToken?: string;
|
providerAuthToken?: string;
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
if (!providerAuthToken) {
|
if (!providerAuthToken) {
|
||||||
throw new Error("Invalid authentication request.");
|
throw new Error("Invalid authentication request.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const decodedToken = <jwt.ProviderAuthJwtPayload>(
|
const decodedToken = <jwt.ProviderAuthJwtPayload>(
|
||||||
jwt.verify(providerAuthToken, await getJwtProviderAuthSecret())
|
jwt.verify(providerAuthToken, await getAuthSecret())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.PROVIDER_TOKEN) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
if (decodedToken.email !== email) {
|
if (decodedToken.email !== email) {
|
||||||
throw new Error("Invalid authentication credentials.")
|
throw new Error("Invalid authentication credentials.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ import {
|
|||||||
getSecretScanningPrivateKey,
|
getSecretScanningPrivateKey,
|
||||||
getSecretScanningWebhookProxy,
|
getSecretScanningWebhookProxy,
|
||||||
getSecretScanningWebhookSecret,
|
getSecretScanningWebhookSecret,
|
||||||
getSiteURL
|
getSiteURL,
|
||||||
} from "./config";
|
} from "./config";
|
||||||
import { setup } from "./utils/setup";
|
import { setup } from "./utils/setup";
|
||||||
import { syncSecretsToThirdPartyServices } from "./queues/integrations/syncSecretsToThirdPartyServices";
|
import { syncSecretsToThirdPartyServices } from "./queues/integrations/syncSecretsToThirdPartyServices";
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import jwt from "jsonwebtoken";
|
|||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import { User } from "../models";
|
import { User } from "../models";
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../utils/errors";
|
||||||
import { getJwtMfaSecret } from "../config";
|
import { getAuthSecret } from "../config";
|
||||||
|
import { AuthTokenType } from "../variables";
|
||||||
|
|
||||||
declare module "jsonwebtoken" {
|
declare module "jsonwebtoken" {
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
@@ -26,9 +27,11 @@ const requireMfaAuth = async (
|
|||||||
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: "Missing Authorization Body in the request header"}))
|
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: "Missing Authorization Body in the request header"}))
|
||||||
|
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
jwt.verify(AUTH_TOKEN_VALUE, await getJwtMfaSecret())
|
jwt.verify(AUTH_TOKEN_VALUE, await getAuthSecret())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.MFA_TOKEN) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId,
|
_id: decodedToken.userId,
|
||||||
}).select("+publicKey");
|
}).select("+publicKey");
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import jwt from "jsonwebtoken";
|
|||||||
import { NextFunction, Request, Response } from "express";
|
import { NextFunction, Request, Response } from "express";
|
||||||
import { User } from "../models";
|
import { User } from "../models";
|
||||||
import { BadRequestError, UnauthorizedRequestError } from "../utils/errors";
|
import { BadRequestError, UnauthorizedRequestError } from "../utils/errors";
|
||||||
import { getJwtSignupSecret } from "../config";
|
import { getAuthSecret } from "../config";
|
||||||
|
import { AuthTokenType } from "../variables";
|
||||||
|
|
||||||
declare module "jsonwebtoken" {
|
declare module "jsonwebtoken" {
|
||||||
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
export interface UserIDJwtPayload extends jwt.JwtPayload {
|
||||||
@@ -27,9 +28,11 @@ const requireSignupAuth = async (
|
|||||||
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: "Missing Authorization Body in the request header"}))
|
if(AUTH_TOKEN_VALUE === null) return next(BadRequestError({message: "Missing Authorization Body in the request header"}))
|
||||||
|
|
||||||
const decodedToken = <jwt.UserIDJwtPayload>(
|
const decodedToken = <jwt.UserIDJwtPayload>(
|
||||||
jwt.verify(AUTH_TOKEN_VALUE, await getJwtSignupSecret())
|
jwt.verify(AUTH_TOKEN_VALUE, await getAuthSecret())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (decodedToken.authTokenType !== AuthTokenType.SIGNUP_TOKEN) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const user = await User.findOne({
|
const user = await User.findOne({
|
||||||
_id: decodedToken.userId,
|
_id: decodedToken.userId,
|
||||||
}).select("+publicKey");
|
}).select("+publicKey");
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
} from "../models";
|
} from "../models";
|
||||||
import { createToken } from "../helpers/auth";
|
import { createToken } from "../helpers/auth";
|
||||||
import {
|
import {
|
||||||
|
getAuthSecret,
|
||||||
getClientIdGitHubLogin,
|
getClientIdGitHubLogin,
|
||||||
getClientIdGitLabLogin,
|
getClientIdGitLabLogin,
|
||||||
getClientIdGoogleLogin,
|
getClientIdGoogleLogin,
|
||||||
@@ -20,13 +21,12 @@ import {
|
|||||||
getClientSecretGitLabLogin,
|
getClientSecretGitLabLogin,
|
||||||
getClientSecretGoogleLogin,
|
getClientSecretGoogleLogin,
|
||||||
getJwtProviderAuthLifetime,
|
getJwtProviderAuthLifetime,
|
||||||
getJwtProviderAuthSecret,
|
|
||||||
getSiteURL,
|
getSiteURL,
|
||||||
getUrlGitLabLogin
|
getUrlGitLabLogin
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { getSSOConfigHelper } from "../ee/helpers/organizations";
|
import { getSSOConfigHelper } from "../ee/helpers/organizations";
|
||||||
import { InternalServerError, OrganizationNotFoundError } from "./errors";
|
import { InternalServerError, OrganizationNotFoundError } from "./errors";
|
||||||
import { ACCEPTED, INTEGRATION_GITHUB_API_URL, INVITED, MEMBER } from "../variables";
|
import { ACCEPTED, AuthTokenType, INTEGRATION_GITHUB_API_URL, INVITED, MEMBER } from "../variables";
|
||||||
import { standardRequest } from "../config/request";
|
import { standardRequest } from "../config/request";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
@@ -131,6 +131,7 @@ const initializePassport = async () => {
|
|||||||
const isUserCompleted = !!user.publicKey;
|
const isUserCompleted = !!user.publicKey;
|
||||||
const providerAuthToken = createToken({
|
const providerAuthToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user._id.toString(),
|
userId: user._id.toString(),
|
||||||
email: user.email,
|
email: user.email,
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@@ -143,7 +144,7 @@ const initializePassport = async () => {
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtProviderAuthLifetime(),
|
expiresIn: await getJwtProviderAuthLifetime(),
|
||||||
secret: await getJwtProviderAuthSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
req.isUserCompleted = isUserCompleted;
|
req.isUserCompleted = isUserCompleted;
|
||||||
@@ -204,6 +205,7 @@ const initializePassport = async () => {
|
|||||||
const isUserCompleted = !!user.publicKey;
|
const isUserCompleted = !!user.publicKey;
|
||||||
const providerAuthToken = createToken({
|
const providerAuthToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user._id.toString(),
|
userId: user._id.toString(),
|
||||||
email: user.email,
|
email: user.email,
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@@ -216,7 +218,7 @@ const initializePassport = async () => {
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtProviderAuthLifetime(),
|
expiresIn: await getJwtProviderAuthLifetime(),
|
||||||
secret: await getJwtProviderAuthSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
req.isUserCompleted = isUserCompleted;
|
req.isUserCompleted = isUserCompleted;
|
||||||
@@ -258,6 +260,7 @@ const initializePassport = async () => {
|
|||||||
const isUserCompleted = !!user.publicKey;
|
const isUserCompleted = !!user.publicKey;
|
||||||
const providerAuthToken = createToken({
|
const providerAuthToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user._id.toString(),
|
userId: user._id.toString(),
|
||||||
email: user.email,
|
email: user.email,
|
||||||
firstName: user.firstName,
|
firstName: user.firstName,
|
||||||
@@ -270,7 +273,7 @@ const initializePassport = async () => {
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtProviderAuthLifetime(),
|
expiresIn: await getJwtProviderAuthLifetime(),
|
||||||
secret: await getJwtProviderAuthSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
req.isUserCompleted = isUserCompleted;
|
req.isUserCompleted = isUserCompleted;
|
||||||
@@ -401,6 +404,7 @@ const initializePassport = async () => {
|
|||||||
const isUserCompleted = !!user.publicKey;
|
const isUserCompleted = !!user.publicKey;
|
||||||
const providerAuthToken = createToken({
|
const providerAuthToken = createToken({
|
||||||
payload: {
|
payload: {
|
||||||
|
authTokenType: AuthTokenType.PROVIDER_TOKEN,
|
||||||
userId: user._id.toString(),
|
userId: user._id.toString(),
|
||||||
email: user.email,
|
email: user.email,
|
||||||
firstName,
|
firstName,
|
||||||
@@ -413,7 +417,7 @@ const initializePassport = async () => {
|
|||||||
} : {})
|
} : {})
|
||||||
},
|
},
|
||||||
expiresIn: await getJwtProviderAuthLifetime(),
|
expiresIn: await getJwtProviderAuthLifetime(),
|
||||||
secret: await getJwtProviderAuthSecret(),
|
secret: await getAuthSecret(),
|
||||||
});
|
});
|
||||||
|
|
||||||
req.isUserCompleted = isUserCompleted;
|
req.isUserCompleted = isUserCompleted;
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
export enum AuthTokenType {
|
||||||
|
ACCESS_TOKEN = "accessToken",
|
||||||
|
REFRESH_TOKEN = "refreshToken",
|
||||||
|
SIGNUP_TOKEN = "signupToken",
|
||||||
|
MFA_TOKEN = "mfaToken",
|
||||||
|
PROVIDER_TOKEN = "providerToken"
|
||||||
|
}
|
||||||
|
|
||||||
export enum AuthMode {
|
export enum AuthMode {
|
||||||
JWT = "jwt",
|
JWT = "jwt",
|
||||||
SERVICE_TOKEN = "serviceToken",
|
SERVICE_TOKEN = "serviceToken",
|
||||||
|
|||||||
@@ -11,43 +11,12 @@ Other environment variables are listed below to increase the functionality of yo
|
|||||||
<Tabs>
|
<Tabs>
|
||||||
<Tab title="Required">
|
<Tab title="Required">
|
||||||
<ParamField query="ENCRYPTION_KEY" type="string" default="none" required>
|
<ParamField query="ENCRYPTION_KEY" type="string" default="none" required>
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16`
|
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16`
|
||||||
</ParamField>
|
</ParamField>
|
||||||
|
|
||||||
{" "}
|
<ParamField query="AUTH_SECRET" type="string" default="none" required>
|
||||||
|
Must be a random 32 byte base64 string. Can be generated with `openssl rand -base64 32`
|
||||||
<ParamField query="JWT_SIGNUP_SECRET" type="string" default="none" required>
|
</ParamField>
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
|
|
||||||
16`
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
{" "}
|
|
||||||
|
|
||||||
<ParamField query="JWT_REFRESH_SECRET" type="string" default="none" required>
|
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
|
|
||||||
16`
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
{" "}
|
|
||||||
|
|
||||||
<ParamField query="JWT_AUTH_SECRET" type="string" default="none" required>
|
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
|
|
||||||
16`
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
{" "}
|
|
||||||
|
|
||||||
<ParamField query="JWT_MFA_SECRET" type="string" default="none" required>
|
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
|
|
||||||
16`
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
{" "}
|
|
||||||
|
|
||||||
<ParamField query="JWT_SERVICE_SECRET" type="string" default="none" required>
|
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
|
|
||||||
16`
|
|
||||||
</ParamField>
|
|
||||||
|
|
||||||
<ParamField query="MONGO_URL" type="string" default="none" required>
|
<ParamField query="MONGO_URL" type="string" default="none" required>
|
||||||
*TLS based connection string is not yet supported
|
*TLS based connection string is not yet supported
|
||||||
@@ -140,9 +109,6 @@ Other environment variables are listed below to increase the functionality of yo
|
|||||||
</Tab>
|
</Tab>
|
||||||
<Tab title="Auth Integrations">
|
<Tab title="Auth Integrations">
|
||||||
To integrate with external auth providers, provide value for the related keys
|
To integrate with external auth providers, provide value for the related keys
|
||||||
<ParamField query="JWT_PROVIDER_AUTH_SECRET" type="string" required>
|
|
||||||
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16`
|
|
||||||
</ParamField>
|
|
||||||
<ParamField query="CLIENT_ID_GOOGLE_LOGIN" type="string" default="none" optional>
|
<ParamField query="CLIENT_ID_GOOGLE_LOGIN" type="string" default="none" optional>
|
||||||
OAuth2 client ID for Google login
|
OAuth2 client ID for Google login
|
||||||
</ParamField>
|
</ParamField>
|
||||||
|
|||||||
Reference in New Issue
Block a user