Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { UserPermissionClaim, UserRoleClaim } from "@dzangolab/fastify-user";

import getMultiTenantConfig from "../../../lib/getMultiTenantConfig";
import getUserService from "../../../lib/getUserService";

Expand All @@ -17,6 +19,18 @@ const createNewSession = (

const tenant = input.userContext.tenant as Tenant;

const userService = getUserService(fastify.config, fastify.slonik, tenant);

const user = await userService.findById(input.userId);

if (user?.disabled) {
throw {
name: "SIGN_IN_FAILED",
message: "user is disabled",
statusCode: 401,
} as FastifyError;
}

if (tenant) {
const request = input.userContext._default.request
.request as FastifyRequest;
Expand All @@ -29,25 +43,29 @@ const createNewSession = (
};
}

const originalResponse = await originalImplementation.createNewSession(
input
);

const userId = originalResponse.getUserId();
if (!input.userContext.roles) {
input.userContext.roles = user?.roles.map(({ role }) => role) || [];
}

const userService = getUserService(fastify.config, fastify.slonik, tenant);
const userRoleBuild = await new UserRoleClaim().build(
input.userId,
input.userContext
);

const user = await userService.findById(userId);
const userPermissionBuild = await new UserPermissionClaim(fastify).build(
input.userId,
input.userContext
);

if (user?.disabled) {
await originalResponse.revokeSession();
input.accessTokenPayload = {
...input.accessTokenPayload,
...userRoleBuild,
...userPermissionBuild,
};

throw {
name: "SIGN_IN_FAILED",
message: "user is disabled",
statusCode: 401,
} as FastifyError;
}
const originalResponse = await originalImplementation.createNewSession(
input
);

return originalResponse;
};
Expand Down
2 changes: 2 additions & 0 deletions packages/user/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ export { default as hasUserPermission } from "./lib/hasUserPermission";
export { default as CustomApiError } from "./customApiError";
export { default as getRolesByNames } from "./lib/getRolesByNames";
export { emailSchema, passwordSchema, roleSchema } from "./schemas";
export { default as UserPermissionClaim } from "./supertokens/utils/userPermissionClaim";
export { default as UserRoleClaim } from "./supertokens/utils/userRoleClaim";

export * from "./constants";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import getUserService from "../../../../lib/getUserService";
import UserPermissionClaim from "../../../utils/userPermissionClaim";
import UserRoleClaim from "../../../utils/userRoleClaim";

import type { FastifyError, FastifyInstance } from "fastify";
import type { SessionRequest } from "supertokens-node/framework/fastify";
Expand All @@ -17,30 +19,46 @@ const createNewSession = (
const request = input.userContext._default.request
.request as SessionRequest;

const originalResponse = await originalImplementation.createNewSession(
input
);

const userId = originalResponse.getUserId();

const userService = getUserService(
request.config,
request.slonik,
request.dbSchema
);

const user = await userService.findById(userId);
const user = await userService.findById(input.userId);

if (user?.disabled) {
await originalResponse.revokeSession();

throw {
name: "SIGN_IN_FAILED",
message: "user is disabled",
statusCode: 401,
} as FastifyError;
}

if (!input.userContext.roles) {
input.userContext.roles = user?.roles.map(({ role }) => role) || [];
}

const userRoleBuild = await new UserRoleClaim().build(
input.userId,
input.userContext
);

const userPermissionBuild = await new UserPermissionClaim(fastify).build(
input.userId,
input.userContext
);

input.accessTokenPayload = {
...input.accessTokenPayload,
...userRoleBuild,
...userPermissionBuild,
};

const originalResponse = await originalImplementation.createNewSession(
input
);

return originalResponse;
};
};
Expand Down
36 changes: 36 additions & 0 deletions packages/user/src/supertokens/utils/userPermissionClaim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { PrimitiveArrayClaim } from "supertokens-node/lib/build/recipe/session/claims";

import RoleService from "../../model/roles/service";

import type { Role, RoleCreateInput, RoleUpdateInput, User } from "../../types";
import type { FastifyInstance } from "fastify";

class UserPermissionClaim extends PrimitiveArrayClaim<string> {
constructor(fastify: FastifyInstance) {
super({
key: "permission",
fetchValue: async (userId, userContext) => {
const roleService = new RoleService<
Role,
RoleCreateInput,
RoleUpdateInput
>(fastify.config, fastify.slonik);

const roles = await roleService.list(undefined, undefined, {
key: "role",
operator: "in",
value: userContext.roles.join(","),
});

return [
...new Set(
roles.data.flatMap(({ permissions }) => permissions || [])
),
];
},
defaultMaxAgeInSeconds: 300,
});
}
}

export default UserPermissionClaim;
15 changes: 15 additions & 0 deletions packages/user/src/supertokens/utils/userRoleClaim.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { PrimitiveArrayClaim } from "supertokens-node/lib/build/recipe/session/claims";

class UserRoleClaim extends PrimitiveArrayClaim<string> {
constructor() {
super({
key: "role",
fetchValue: async (userId: string, userContext) => {
return userContext.roles;
},
defaultMaxAgeInSeconds: 300,
});
}
}

export default UserRoleClaim;
1 change: 1 addition & 0 deletions packages/user/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default defineConfig(({ mode }) => {
slonik: "Slonik",
"supertokens-node": "SupertokensNode",
"supertokens-node/framework/fastify": "SupertokensFastify",
"supertokens-node/lib/build/recipe/session/claims": "claims",
"supertokens-node/recipe/emailverification": "EmailVerification",
"supertokens-node/recipe/session/framework/fastify":
"SupertokensSessionFastify",
Expand Down