mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-04 22:26:15 +00:00
Feat: Org Scoped JWT Tokens
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
|
import jwt from "jsonwebtoken";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
import { authRateLimit } from "@app/server/config/rateLimiter";
|
import { authRateLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { AuthModeJwtTokenPayload } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
export const registerLoginRouter = async (server: FastifyZodProvider) => {
|
export const registerLoginRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
@@ -34,6 +37,67 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/select-organization",
|
||||||
|
config: {
|
||||||
|
rateLimit: authRateLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
body: z.object({
|
||||||
|
organizationId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
token: z.string()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req, res) => {
|
||||||
|
const cfg = getConfig();
|
||||||
|
|
||||||
|
if (!req.headers.authorization) throw new UnauthorizedError({ name: "Authorization header is required" });
|
||||||
|
if (!req.headers["user-agent"]) throw new UnauthorizedError({ name: "user agent header is required" });
|
||||||
|
|
||||||
|
const userAgent = req.headers["user-agent"];
|
||||||
|
const authToken = req.headers.authorization.slice(7); // slice of after Bearer
|
||||||
|
|
||||||
|
// The decoded JWT token, which contains the auth method.
|
||||||
|
const decodedToken = jwt.verify(authToken, cfg.AUTH_SECRET) as AuthModeJwtTokenPayload;
|
||||||
|
|
||||||
|
if (decodedToken.organizationId) {
|
||||||
|
throw new UnauthorizedError({ message: "You have already selected an organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await server.services.user.getMe(decodedToken.userId);
|
||||||
|
|
||||||
|
// Check if the user actually has access to the specified organization.
|
||||||
|
const userOrgs = await server.services.org.findAllOrganizationOfUser(user.id);
|
||||||
|
|
||||||
|
if (!userOrgs.some((org) => org.id === req.body.organizationId)) {
|
||||||
|
throw new UnauthorizedError({ message: "User does not have access to the organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
await server.services.authToken.clearTokenSessionById(decodedToken.userId, decodedToken.tokenVersionId);
|
||||||
|
const tokens = await server.services.login.generateUserTokens({
|
||||||
|
authMethod: decodedToken.authMethod,
|
||||||
|
user,
|
||||||
|
userAgent,
|
||||||
|
ip: req.realIp,
|
||||||
|
organizationId: req.body.organizationId
|
||||||
|
});
|
||||||
|
|
||||||
|
void res.setCookie("jid", tokens.refresh, {
|
||||||
|
httpOnly: true,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "strict",
|
||||||
|
secure: cfg.HTTPS_ENABLED
|
||||||
|
});
|
||||||
|
|
||||||
|
return { token: tokens.access };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: "/login2",
|
url: "/login2",
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { UnauthorizedError } from "@app/lib/errors";
|
import { UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { AuthModeJwtTokenPayload } from "../auth/auth-type";
|
import { AuthMethod, AuthModeJwtTokenPayload } from "../auth/auth-type";
|
||||||
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TTokenDALFactory } from "./auth-token-dal";
|
import { TTokenDALFactory } from "./auth-token-dal";
|
||||||
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
|
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
|
||||||
@@ -14,6 +15,7 @@ import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenFo
|
|||||||
type TAuthTokenServiceFactoryDep = {
|
type TAuthTokenServiceFactoryDep = {
|
||||||
tokenDAL: TTokenDALFactory;
|
tokenDAL: TTokenDALFactory;
|
||||||
userDAL: Pick<TUserDALFactory, "findById">;
|
userDAL: Pick<TUserDALFactory, "findById">;
|
||||||
|
orgDAL: TOrgDALFactory;
|
||||||
};
|
};
|
||||||
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
export type TAuthTokenServiceFactory = ReturnType<typeof tokenServiceFactory>;
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFactoryDep) => {
|
export const tokenServiceFactory = ({ tokenDAL, userDAL, orgDAL }: TAuthTokenServiceFactoryDep) => {
|
||||||
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
|
const createTokenForUser = async ({ type, userId, orgId }: TCreateTokenForUserDTO) => {
|
||||||
const { token, ...tkCfg } = getTokenConfig(type);
|
const { token, ...tkCfg } = getTokenConfig(type);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
@@ -135,12 +137,25 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL }: TAuthTokenServiceFact
|
|||||||
id: token.tokenVersionId,
|
id: token.tokenVersionId,
|
||||||
userId: token.userId
|
userId: token.userId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
if (!session) throw new UnauthorizedError({ name: "Session not found" });
|
||||||
if (token.accessVersion !== session.accessVersion) throw new UnauthorizedError({ name: "Stale session" });
|
if (token.accessVersion !== session.accessVersion) throw new UnauthorizedError({ name: "Stale session" });
|
||||||
|
|
||||||
const user = await userDAL.findById(session.userId);
|
const user = await userDAL.findById(session.userId);
|
||||||
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
if (!user || !user.isAccepted) throw new UnauthorizedError({ name: "Token user not found" });
|
||||||
|
|
||||||
|
if (token.organizationId) {
|
||||||
|
const organization = await orgDAL.findById(token.organizationId);
|
||||||
|
|
||||||
|
if (organization.authEnforced) {
|
||||||
|
const tokenAuthMode = token.authMethod;
|
||||||
|
|
||||||
|
if (![AuthMethod.AZURE_SAML, AuthMethod.OKTA_SAML, AuthMethod.JUMPCLOUD_SAML].includes(tokenAuthMode)) {
|
||||||
|
throw new UnauthorizedError({ name: "Organization enforces SAML" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId };
|
return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ export const validateProviderAuthToken = (providerToken: string, username?: stri
|
|||||||
if (decodedToken.username !== username) throw new Error("Invalid auth credentials");
|
if (decodedToken.username !== username) throw new Error("Invalid auth credentials");
|
||||||
|
|
||||||
if (decodedToken.organizationId) {
|
if (decodedToken.organizationId) {
|
||||||
return { orgId: decodedToken.organizationId };
|
return { orgId: decodedToken.organizationId, authMethod: decodedToken.authMethod };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return { authMethod: decodedToken.authMethod, orgId: null };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
|
export const validateSignUpAuthorization = (token: string, userId: string, validate = true) => {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
TOauthLoginDTO,
|
TOauthLoginDTO,
|
||||||
TVerifyMfaTokenDTO
|
TVerifyMfaTokenDTO
|
||||||
} from "./auth-login-type";
|
} from "./auth-login-type";
|
||||||
import { AuthMethod, AuthTokenType } from "./auth-type";
|
import { AuthMethod, AuthModeMfaJwtTokenPayload, AuthTokenType } from "./auth-type";
|
||||||
|
|
||||||
type TAuthLoginServiceFactoryDep = {
|
type TAuthLoginServiceFactoryDep = {
|
||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
@@ -83,12 +83,14 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
user,
|
user,
|
||||||
ip,
|
ip,
|
||||||
userAgent,
|
userAgent,
|
||||||
organizationId
|
organizationId,
|
||||||
|
authMethod
|
||||||
}: {
|
}: {
|
||||||
user: TUsers;
|
user: TUsers;
|
||||||
ip: string;
|
ip: string;
|
||||||
userAgent: string;
|
userAgent: string;
|
||||||
organizationId?: string;
|
organizationId?: string;
|
||||||
|
authMethod: AuthMethod;
|
||||||
}) => {
|
}) => {
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
await updateUserDeviceSession(user, ip, userAgent);
|
await updateUserDeviceSession(user, ip, userAgent);
|
||||||
@@ -98,8 +100,10 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
userId: user.id
|
userId: user.id
|
||||||
});
|
});
|
||||||
if (!tokenSession) throw new Error("Failed to create token");
|
if (!tokenSession) throw new Error("Failed to create token");
|
||||||
|
|
||||||
const accessToken = jwt.sign(
|
const accessToken = jwt.sign(
|
||||||
{
|
{
|
||||||
|
authMethod,
|
||||||
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
tokenVersionId: tokenSession.id,
|
tokenVersionId: tokenSession.id,
|
||||||
@@ -112,6 +116,7 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
|
|
||||||
const refreshToken = jwt.sign(
|
const refreshToken = jwt.sign(
|
||||||
{
|
{
|
||||||
|
authMethod,
|
||||||
authTokenType: AuthTokenType.REFRESH_TOKEN,
|
authTokenType: AuthTokenType.REFRESH_TOKEN,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
tokenVersionId: tokenSession.id,
|
tokenVersionId: tokenSession.id,
|
||||||
@@ -158,9 +163,9 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
const loginExchangeClientProof = async ({
|
const loginExchangeClientProof = async ({
|
||||||
email,
|
email,
|
||||||
clientProof,
|
clientProof,
|
||||||
providerAuthToken,
|
|
||||||
ip,
|
ip,
|
||||||
userAgent
|
userAgent,
|
||||||
|
providerAuthToken
|
||||||
}: TLoginClientProofDTO) => {
|
}: TLoginClientProofDTO) => {
|
||||||
const userEnc = await userDAL.findUserEncKeyByUsername({
|
const userEnc = await userDAL.findUserEncKeyByUsername({
|
||||||
username: email
|
username: email
|
||||||
@@ -168,14 +173,14 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
if (!userEnc) throw new Error("Failed to find user");
|
if (!userEnc) throw new Error("Failed to find user");
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
|
|
||||||
let organizationId;
|
// let organizationId;
|
||||||
if (!userEnc.authMethods?.includes(AuthMethod.EMAIL)) {
|
|
||||||
const { orgId } = validateProviderAuthToken(providerAuthToken as string, email);
|
// let authMethod = (providerAuthToken as AuthMethod) || AuthMethod.EMAIL;
|
||||||
organizationId = orgId;
|
|
||||||
} else if (providerAuthToken) {
|
let authMethod = AuthMethod.EMAIL;
|
||||||
// SAML SSO
|
|
||||||
const { orgId } = validateProviderAuthToken(providerAuthToken, email);
|
if (providerAuthToken) {
|
||||||
organizationId = orgId;
|
authMethod = validateProviderAuthToken(providerAuthToken, email).authMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
|
if (!userEnc.serverPrivateKey || !userEnc.clientPublicKey) throw new Error("Failed to authenticate. Try again?");
|
||||||
@@ -196,9 +201,9 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
if (userEnc.isMfaEnabled && userEnc.email) {
|
if (userEnc.isMfaEnabled && userEnc.email) {
|
||||||
const mfaToken = jwt.sign(
|
const mfaToken = jwt.sign(
|
||||||
{
|
{
|
||||||
|
authMethod,
|
||||||
authTokenType: AuthTokenType.MFA_TOKEN,
|
authTokenType: AuthTokenType.MFA_TOKEN,
|
||||||
userId: userEnc.userId,
|
userId: userEnc.userId
|
||||||
organizationId
|
|
||||||
},
|
},
|
||||||
cfg.AUTH_SECRET,
|
cfg.AUTH_SECRET,
|
||||||
{
|
{
|
||||||
@@ -221,7 +226,7 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
},
|
},
|
||||||
ip,
|
ip,
|
||||||
userAgent,
|
userAgent,
|
||||||
organizationId
|
authMethod
|
||||||
});
|
});
|
||||||
|
|
||||||
return { token, isMfaEnabled: false, user: userEnc } as const;
|
return { token, isMfaEnabled: false, user: userEnc } as const;
|
||||||
@@ -250,6 +255,9 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
userId,
|
userId,
|
||||||
code: mfaToken
|
code: mfaToken
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const decodedToken = jwt.verify(mfaToken, getConfig().AUTH_SECRET) as AuthModeMfaJwtTokenPayload;
|
||||||
|
|
||||||
const userEnc = await userDAL.findUserEncKeyByUserId(userId);
|
const userEnc = await userDAL.findUserEncKeyByUserId(userId);
|
||||||
if (!userEnc) throw new Error("Failed to authenticate user");
|
if (!userEnc) throw new Error("Failed to authenticate user");
|
||||||
|
|
||||||
@@ -260,7 +268,8 @@ export const authLoginServiceFactory = ({ userDAL, tokenService, smtpService }:
|
|||||||
},
|
},
|
||||||
ip,
|
ip,
|
||||||
userAgent,
|
userAgent,
|
||||||
organizationId: orgId
|
organizationId: orgId,
|
||||||
|
authMethod: decodedToken.authMethod
|
||||||
});
|
});
|
||||||
|
|
||||||
return { token, user: userEnc };
|
return { token, user: userEnc };
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ export const authSignupServiceFactory = ({
|
|||||||
|
|
||||||
const accessToken = jwt.sign(
|
const accessToken = jwt.sign(
|
||||||
{
|
{
|
||||||
|
authMethod: AuthMethod.EMAIL,
|
||||||
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
userId: updateduser.info.id,
|
userId: updateduser.info.id,
|
||||||
tokenVersionId: tokenSession.id,
|
tokenVersionId: tokenSession.id,
|
||||||
@@ -277,6 +278,7 @@ export const authSignupServiceFactory = ({
|
|||||||
|
|
||||||
const accessToken = jwt.sign(
|
const accessToken = jwt.sign(
|
||||||
{
|
{
|
||||||
|
authMethod: AuthMethod.EMAIL,
|
||||||
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
authTokenType: AuthTokenType.ACCESS_TOKEN,
|
||||||
userId: updateduser.info.id,
|
userId: updateduser.info.id,
|
||||||
tokenVersionId: tokenSession.id,
|
tokenVersionId: tokenSession.id,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export enum ActorType { // would extend to AWS, Azure, ...
|
|||||||
|
|
||||||
export type AuthModeJwtTokenPayload = {
|
export type AuthModeJwtTokenPayload = {
|
||||||
authTokenType: AuthTokenType.ACCESS_TOKEN;
|
authTokenType: AuthTokenType.ACCESS_TOKEN;
|
||||||
|
authMethod: AuthMethod;
|
||||||
userId: string;
|
userId: string;
|
||||||
tokenVersionId: string;
|
tokenVersionId: string;
|
||||||
accessVersion: number;
|
accessVersion: number;
|
||||||
@@ -48,12 +49,15 @@ export type AuthModeJwtTokenPayload = {
|
|||||||
|
|
||||||
export type AuthModeMfaJwtTokenPayload = {
|
export type AuthModeMfaJwtTokenPayload = {
|
||||||
authTokenType: AuthTokenType.MFA_TOKEN;
|
authTokenType: AuthTokenType.MFA_TOKEN;
|
||||||
|
authMethod: AuthMethod;
|
||||||
userId: string;
|
userId: string;
|
||||||
organizationId?: string;
|
organizationId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AuthModeRefreshJwtTokenPayload = {
|
export type AuthModeRefreshJwtTokenPayload = {
|
||||||
|
// authMode
|
||||||
authTokenType: AuthTokenType.REFRESH_TOKEN;
|
authTokenType: AuthTokenType.REFRESH_TOKEN;
|
||||||
|
authMethod: AuthMethod;
|
||||||
userId: string;
|
userId: string;
|
||||||
tokenVersionId: string;
|
tokenVersionId: string;
|
||||||
refreshVersion: number;
|
refreshVersion: number;
|
||||||
@@ -63,6 +67,8 @@ export type AuthModeRefreshJwtTokenPayload = {
|
|||||||
export type AuthModeProviderJwtTokenPayload = {
|
export type AuthModeProviderJwtTokenPayload = {
|
||||||
authTokenType: AuthTokenType.PROVIDER_TOKEN;
|
authTokenType: AuthTokenType.PROVIDER_TOKEN;
|
||||||
username: string;
|
username: string;
|
||||||
|
authMethod: AuthMethod;
|
||||||
|
email: string;
|
||||||
organizationId?: string;
|
organizationId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { ActorType } from "../auth/auth-type";
|
import { ActorType } from "../auth/auth-type";
|
||||||
|
import { TProjectDALFactory } from "../project/project-dal";
|
||||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TServiceTokenDALFactory } from "./service-token-dal";
|
import { TServiceTokenDALFactory } from "./service-token-dal";
|
||||||
@@ -24,6 +25,7 @@ type TServiceTokenServiceFactoryDep = {
|
|||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
|
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TServiceTokenServiceFactory = ReturnType<typeof serviceTokenServiceFactory>;
|
export type TServiceTokenServiceFactory = ReturnType<typeof serviceTokenServiceFactory>;
|
||||||
@@ -32,7 +34,8 @@ export const serviceTokenServiceFactory = ({
|
|||||||
serviceTokenDAL,
|
serviceTokenDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
projectEnvDAL
|
projectEnvDAL,
|
||||||
|
projectDAL
|
||||||
}: TServiceTokenServiceFactoryDep) => {
|
}: TServiceTokenServiceFactoryDep) => {
|
||||||
const createServiceToken = async ({
|
const createServiceToken = async ({
|
||||||
iv,
|
iv,
|
||||||
@@ -132,6 +135,9 @@ export const serviceTokenServiceFactory = ({
|
|||||||
const serviceToken = await serviceTokenDAL.findById(TOKEN_IDENTIFIER);
|
const serviceToken = await serviceTokenDAL.findById(TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
if (!serviceToken) throw new UnauthorizedError();
|
if (!serviceToken) throw new UnauthorizedError();
|
||||||
|
const project = await projectDAL.findById(serviceToken.projectId);
|
||||||
|
|
||||||
|
if (!project) throw new UnauthorizedError({ message: "Service token project not found" });
|
||||||
|
|
||||||
if (serviceToken.expiresAt && new Date(serviceToken.expiresAt) < new Date()) {
|
if (serviceToken.expiresAt && new Date(serviceToken.expiresAt) < new Date()) {
|
||||||
await serviceTokenDAL.deleteById(serviceToken.id);
|
await serviceTokenDAL.deleteById(serviceToken.id);
|
||||||
@@ -144,7 +150,7 @@ export const serviceTokenServiceFactory = ({
|
|||||||
lastUsed: new Date()
|
lastUsed: new Date()
|
||||||
});
|
});
|
||||||
|
|
||||||
return { ...serviceToken, lastUsed: updatedToken.lastUsed };
|
return { ...serviceToken, lastUsed: updatedToken.lastUsed, orgId: project.orgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ export const PermissionDeniedBanner = ({ containerClassName, className, children
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
"container h-full mx-auto flex justify-center items-center",
|
"container mx-auto flex h-full items-center justify-center",
|
||||||
containerClassName
|
containerClassName
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
"rounded-md bg-mineshaft-800 text-bunker-300 p-16 flex space-x-12 items-end",
|
"flex items-end space-x-12 rounded-md bg-mineshaft-800 p-16 text-bunker-300",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -27,10 +27,11 @@ export const PermissionDeniedBanner = ({ containerClassName, className, children
|
|||||||
<FontAwesomeIcon icon={faLock} size="6x" />
|
<FontAwesomeIcon icon={faLock} size="6x" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-4xl font-medium mb-2">Access Restricted</div>
|
<div className="mb-2 text-4xl font-medium">Access Restricted</div>
|
||||||
{children || (
|
{children || (
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
Your role has limited permissions, please <br/> contact your administrator to gain access
|
Your role has limited permissions, please <br /> contact your administrator to gain
|
||||||
|
access
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user