feat: abstracted jwt service (#13016)

* remove unused JwtModule from the auth module

* feat: create abstracted jwt service

* refactor: tokens module and service use new jwt service

* refactor: oauth-client module and repository use new jwt service

* implement Morgans requests
This commit is contained in:
Lauris Skraucis 2024-01-04 11:28:36 +02:00 committed by GitHub
parent 78ecd2c9e1
commit 55327ce035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 45 deletions

View File

@ -2,6 +2,7 @@ import { AppLoggerMiddleware } from "@/app.logger.middleware";
import appConfig from "@/config/app";
import { AuthModule } from "@/modules/auth/auth.module";
import { EndpointsModule } from "@/modules/endpoints.module";
import { JwtModule } from "@/modules/jwt/jwt.module";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
@ -18,6 +19,7 @@ import { AppController } from "./app.controller";
PrismaModule,
EndpointsModule,
AuthModule,
JwtModule,
],
controllers: [AppController],
})

View File

@ -9,18 +9,10 @@ import { OAuthFlowService } from "@/modules/oauth-clients/services/oauth-flow.se
import { TokensModule } from "@/modules/tokens/tokens.module";
import { UsersModule } from "@/modules/users/users.module";
import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
import { PassportModule } from "@nestjs/passport";
@Module({
imports: [
PassportModule,
JwtModule.register({}),
ApiKeyModule,
UsersModule,
MembershipsModule,
TokensModule,
],
imports: [PassportModule, ApiKeyModule, UsersModule, MembershipsModule, TokensModule],
providers: [
ApiKeyAuthStrategy,
NextAuthGuard,

View File

@ -0,0 +1,12 @@
import { getEnv } from "@/env";
import { JwtService } from "@/modules/jwt/jwt.service";
import { Global, Module } from "@nestjs/common";
import { JwtModule as NestJwtModule } from "@nestjs/jwt";
@Global()
@Module({
imports: [NestJwtModule.register({ secret: getEnv("JWT_SECRET") })],
providers: [JwtService],
exports: [JwtService],
})
export class JwtModule {}

View File

@ -0,0 +1,31 @@
import { Injectable } from "@nestjs/common";
import { JwtService as NestJwtService } from "@nestjs/jwt";
@Injectable()
export class JwtService {
constructor(private readonly nestJwtService: NestJwtService) {}
signAccessToken(payload: Payload) {
const accessToken = this.sign({ type: "access_token", ...payload });
return accessToken;
}
signRefreshToken(payload: Payload) {
const refreshToken = this.sign({ type: "refresh_token", ...payload });
return refreshToken;
}
sign(payload: Payload) {
const issuedAtTime = this.getIssuedAtTime();
const token = this.nestJwtService.sign({ ...payload, iat: issuedAtTime });
return token;
}
getIssuedAtTime() {
// divided by 1000 because iat (issued at time) is in seconds (not milliseconds) as informed by JWT speficication
return Math.floor(Date.now() / 1000);
}
}
type Payload = Record<string | number | symbol, any>;

View File

@ -1,4 +1,3 @@
import { getEnv } from "@/env";
import { AuthModule } from "@/modules/auth/auth.module";
import { MembershipsModule } from "@/modules/memberships/memberships.module";
import { OAuthClientUsersController } from "@/modules/oauth-clients/controllers/oauth-client-users/oauth-client-users.controller";
@ -11,17 +10,10 @@ import { PrismaModule } from "@/modules/prisma/prisma.module";
import { TokensRepository } from "@/modules/tokens/tokens.repository";
import { UsersModule } from "@/modules/users/users.module";
import { Global, Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
@Global()
@Module({
imports: [
PrismaModule,
AuthModule,
UsersModule,
MembershipsModule,
JwtModule.register({ secret: getEnv("JWT_SECRET") }),
],
imports: [PrismaModule, AuthModule, UsersModule, MembershipsModule],
providers: [OAuthClientRepository, OAuthClientCredentialsGuard, TokensRepository, OAuthFlowService],
controllers: [OAuthClientUsersController, OAuthClientsController, OAuthFlowController],
exports: [OAuthClientRepository, OAuthClientCredentialsGuard],

View File

@ -1,7 +1,7 @@
import { JwtService } from "@/modules/jwt/jwt.service";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { Injectable } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import type { PlatformOAuthClient } from "@prisma/client";
import type { CreateOAuthClientInput } from "@calcom/platform-types";
@ -18,7 +18,7 @@ export class OAuthClientRepository {
return this.dbWrite.prisma.platformOAuthClient.create({
data: {
...data,
secret: await this.jwtService.signAsync(JSON.stringify(data)),
secret: this.jwtService.sign(data),
organizationId,
},
});

View File

@ -1,16 +1,9 @@
import { getEnv } from "@/env";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import { TokensRepository } from "@/modules/tokens/tokens.repository";
import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
@Module({
imports: [
JwtModule.register({
secret: getEnv("NEXTAUTH_SECRET"),
}),
PrismaModule,
],
imports: [PrismaModule],
providers: [TokensRepository],
exports: [TokensRepository],
})

View File

@ -1,7 +1,7 @@
import { JwtService } from "@/modules/jwt/jwt.service";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
import { Injectable } from "@nestjs/common";
import { JwtService } from "@nestjs/jwt";
import { PlatformAuthorizationToken } from "@prisma/client";
import { DateTime } from "luxon";
@ -43,14 +43,10 @@ export class TokensRepository {
const accessExpiry = DateTime.now().plus({ days: 1 }).startOf("day").toJSDate();
const refreshExpiry = DateTime.now().plus({ year: 1 }).startOf("day").toJSDate();
const issuedAtTime = Math.floor(Date.now() / 1000);
const [accessToken, refreshToken] = await this.dbWrite.prisma.$transaction([
this.dbWrite.prisma.accessToken.create({
data: {
secret: this.jwtService.sign(
JSON.stringify({ type: "access_token", clientId, ownerId, iat: issuedAtTime })
),
secret: this.jwtService.signAccessToken({ clientId, ownerId }),
expiresAt: accessExpiry,
client: { connect: { id: clientId } },
owner: { connect: { id: ownerId } },
@ -58,9 +54,7 @@ export class TokensRepository {
}),
this.dbWrite.prisma.refreshToken.create({
data: {
secret: this.jwtService.sign(
JSON.stringify({ type: "refresh_token", clientId, ownerId, iat: issuedAtTime })
),
secret: this.jwtService.signRefreshToken({ clientId, ownerId }),
expiresAt: refreshExpiry,
client: { connect: { id: clientId } },
owner: { connect: { id: ownerId } },
@ -103,8 +97,6 @@ export class TokensRepository {
const accessExpiry = DateTime.now().plus({ days: 1 }).startOf("day").toJSDate();
const refreshExpiry = DateTime.now().plus({ year: 1 }).startOf("day").toJSDate();
const issuedAtTime = Math.floor(Date.now() / 1000);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, _refresh, accessToken, refreshToken] = await this.dbWrite.prisma.$transaction([
this.dbWrite.prisma.accessToken.deleteMany({
@ -113,9 +105,7 @@ export class TokensRepository {
this.dbWrite.prisma.refreshToken.delete({ where: { secret: refreshTokenSecret } }),
this.dbWrite.prisma.accessToken.create({
data: {
secret: this.jwtService.sign(
JSON.stringify({ type: "access_token", clientId, userId: tokenUserId, iat: issuedAtTime })
),
secret: this.jwtService.signAccessToken({ clientId, userId: tokenUserId }),
expiresAt: accessExpiry,
client: { connect: { id: clientId } },
owner: { connect: { id: tokenUserId } },
@ -123,9 +113,7 @@ export class TokensRepository {
}),
this.dbWrite.prisma.refreshToken.create({
data: {
secret: this.jwtService.sign(
JSON.stringify({ type: "refresh_token", clientId, userId: tokenUserId, iat: issuedAtTime })
),
secret: this.jwtService.signRefreshToken({ clientId, userId: tokenUserId }),
expiresAt: refreshExpiry,
client: { connect: { id: clientId } },
owner: { connect: { id: tokenUserId } },