diff --git a/apps/backend/docker-compose.yml b/apps/backend/docker-compose.yml index 89d35c44..a7161f5b 100644 --- a/apps/backend/docker-compose.yml +++ b/apps/backend/docker-compose.yml @@ -9,7 +9,7 @@ services: POSTGRES_USER: ${POSTGRES_USER:-safeswap_user} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-safeswap_password} ports: - - "${POSTGRES_PORT:-5432}:5432" + - "${POSTGRES_PORT:-5433}:5432" volumes: - safeswap_data:/var/lib/postgresql/data restart: unless-stopped diff --git a/apps/backend/src/auth/auth.controller.ts b/apps/backend/src/auth/auth.controller.ts new file mode 100644 index 00000000..e26a4afc --- /dev/null +++ b/apps/backend/src/auth/auth.controller.ts @@ -0,0 +1,37 @@ +import { + Body, + Controller, + Get, + Post, + Request, + UseGuards, +} from "@nestjs/common"; +import { AuthService } from "./auth.service"; +import { JwtAuthGuard } from "./guards/jwt-auth.guard"; + +@Controller("auth") +export class AuthController { + constructor(private readonly authService: AuthService) {} + + @Post("token") + getToken(@Body() body: { userId: string; walletAddress?: string }) { + // This is a simplified version for testing only + // In a real application, you'd validate the user or wallet signature + const token = this.authService.signJwt({ + sub: body.userId, + walletAddress: body.walletAddress, + }); + + return { token }; + } + + @UseGuards(JwtAuthGuard) + @Get("profile") + getProfile(@Request() req) { + // The JWT payload is attached to the request by the JwtStrategy + return { + message: "You have successfully accessed a protected route!", + user: req.user, + }; + } +} diff --git a/apps/backend/src/auth/auth.module.ts b/apps/backend/src/auth/auth.module.ts new file mode 100644 index 00000000..c0ae6a93 --- /dev/null +++ b/apps/backend/src/auth/auth.module.ts @@ -0,0 +1,27 @@ +import { Module } from "@nestjs/common"; +import { ConfigModule, ConfigService } from "@nestjs/config"; +import { JwtModule } from "@nestjs/jwt"; +import { PassportModule } from "@nestjs/passport"; +import { AuthController } from "./auth.controller"; +import { AuthService } from "./auth.service"; +import { JwtStrategy } from "./strategies/jwt.strategy"; + +@Module({ + imports: [ + ConfigModule, + PassportModule.register({ defaultStrategy: "jwt" }), + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: async (configService: ConfigService) => ({ + secret: configService.get("JWT_SECRET"), + signOptions: { + expiresIn: configService.get("JWT_EXPIRATION") || "1h", // Default to 1 hour if not set, + }, + }), + }), + ], + controllers: [AuthController], + providers: [AuthService, JwtStrategy], +}) +export class AuthModule {} diff --git a/apps/backend/src/auth/auth.service.ts b/apps/backend/src/auth/auth.service.ts new file mode 100644 index 00000000..f651b123 --- /dev/null +++ b/apps/backend/src/auth/auth.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { JwtService } from "@nestjs/jwt"; + +interface JwtPayload { + sub: string; + walletAddress?: string; +} + +@Injectable() +export class AuthService { + constructor( + private jwtService: JwtService, + private configService: ConfigService, + ) {} + + /** + * Signs a JWT token with the provided payload + * @param payload Data to include in the JWT + * @returns Signed JWT token + */ + + signJwt(payload: JwtPayload): string { + return this.jwtService.sign(payload, { + secret: this.configService.get("JWT_SECRET"), + expiresIn: this.configService.get("JWT_EXPIRATION"), + }); + } + + // Future methods for wallet authentication will go here +} diff --git a/apps/backend/src/auth/guards/jwt-auth.guard.ts b/apps/backend/src/auth/guards/jwt-auth.guard.ts new file mode 100644 index 00000000..7ef592dc --- /dev/null +++ b/apps/backend/src/auth/guards/jwt-auth.guard.ts @@ -0,0 +1,5 @@ +import { Injectable, UnauthorizedException } from "@nestjs/common"; +import { AuthGuard } from "@nestjs/passport"; + +@Injectable() +export class JwtAuthGuard extends AuthGuard("jwt") {} diff --git a/apps/backend/src/auth/interfaces/jwt-payload.interface.ts b/apps/backend/src/auth/interfaces/jwt-payload.interface.ts new file mode 100644 index 00000000..fb867857 --- /dev/null +++ b/apps/backend/src/auth/interfaces/jwt-payload.interface.ts @@ -0,0 +1,4 @@ +export interface JwtPayload { + sub: string; // User ID + walletAddress?: string; // For future wallet integration +} diff --git a/apps/backend/src/auth/strategies/jwt.strategy.ts b/apps/backend/src/auth/strategies/jwt.strategy.ts new file mode 100644 index 00000000..a73cfdc6 --- /dev/null +++ b/apps/backend/src/auth/strategies/jwt.strategy.ts @@ -0,0 +1,27 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { PassportStrategy } from "@nestjs/passport"; +import { ExtractJwt, Strategy } from "passport-jwt"; + +interface JwtPayload { + sub: string; + walletAddress?: string; +} + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor(private configService: ConfigService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: configService.get("JWT_SECRET"), + }); + } + + // This method will be called for each request with a valid JWT token + async validate(payload: JwtPayload) { + // This is a placeholder for future wallet validation logic + // For now, simply return the payload which will be attached to the request object + return payload; + } +} diff --git a/apps/backend/src/core/core.module.ts b/apps/backend/src/core/core.module.ts index 25d89bb4..917de9fe 100644 --- a/apps/backend/src/core/core.module.ts +++ b/apps/backend/src/core/core.module.ts @@ -11,8 +11,10 @@ import { IS_DEV_ENV } from "src/shared/utils/is-dev.util"; import { getGraphQLConfig } from "./config/graphql.config"; import { PrismaModule } from "./prisma/prisma.module"; +import { AuthModule } from "src/auth/auth.module"; @Module({ imports: [ + AuthModule, ConfigModule.forRoot({ ignoreEnvFile: !IS_DEV_ENV, isGlobal: true, diff --git a/apps/backend/src/core/graphql/schema.gql b/apps/backend/src/core/graphql/schema.gql index d7b25bb5..3248a1fa 100644 --- a/apps/backend/src/core/graphql/schema.gql +++ b/apps/backend/src/core/graphql/schema.gql @@ -3,33 +3,33 @@ # ------------------------------------------------------ type Category { - createdAt: DateTime! - id: ID! - imageUrl: String - name: String! - updatedAt: DateTime! + createdAt: DateTime! + id: ID! + imageUrl: String + name: String! + updatedAt: DateTime! } input CreateCategoryInput { - name: String! + name: String! } input CreateProductInput { - categoryId: String! - description: String - name: String! - price: Float! - slug: String! + categoryId: String! + description: String + name: String! + price: Float! + slug: String! } input CreateUserInput { - country: String! - email: String! - isSeller: Boolean! = false - name: String! - surname: String! - telegramUsername: String - walletAddress: String! + country: String! + email: String! + isSeller: Boolean! = false + name: String! + surname: String! + telegramUsername: String + walletAddress: String! } """ @@ -38,66 +38,66 @@ A date-time string at UTC, such as 2019-12-03T09:54:33Z, compliant with the date scalar DateTime type Mutation { - createCategory(data: CreateCategoryInput!): Category! - createProduct(data: CreateProductInput!): ProductDTO! - createProductImage(createProductImage: ProductImageDTO!): ProductImage! - createUser(data: CreateUserInput!): User! - updateUser(data: UpdateUserInput!, walletAddress: String!): User! + createCategory(data: CreateCategoryInput!): Category! + createProduct(data: CreateProductInput!): ProductDTO! + createProductImage(createProductImage: ProductImageDTO!): ProductImage! + createUser(data: CreateUserInput!): User! + updateUser(data: UpdateUserInput!, walletAddress: String!): User! } type ProductDTO { - categoryId: String! - createdAt: DateTime! - description: String - id: ID! - name: String! - price: Float! - slug: String! - updatedAt: DateTime! + categoryId: String! + createdAt: DateTime! + description: String + id: ID! + name: String! + price: Float! + slug: String! + updatedAt: DateTime! } type ProductImage { - createdAt: DateTime! - id: ID! - imageUrl: String! - productId: String! - updatedAt: DateTime! + createdAt: DateTime! + id: ID! + imageUrl: String! + productId: String! + updatedAt: DateTime! } input ProductImageDTO { - imageUrl: String! - productId: String! + imageUrl: String! + productId: String! } type Query { - categories: [Category!]! - category(id: String!): Category - product(id: String!): ProductDTO - productImage(id: String!): ProductImage - productImages: [ProductImage!]! - products: [ProductDTO!]! - user(walletAddress: String!): User - users: [User!]! + categories: [Category!]! + category(id: String!): Category + product(id: String!): ProductDTO + productImage(id: String!): ProductImage + productImages: [ProductImage!]! + products: [ProductDTO!]! + user(walletAddress: String!): User + users: [User!]! } input UpdateUserInput { - country: String - email: String - isSeller: Boolean = false - name: String - surname: String - telegramUsername: String - walletAddress: String + country: String + email: String + isSeller: Boolean = false + name: String + surname: String + telegramUsername: String + walletAddress: String } type User { - country: String! - createdAt: DateTime! - email: String! - isSeller: Boolean! - name: String! - surname: String! - telegramUsername: String - updatedAt: DateTime! - walletAddress: String! -} + country: String! + createdAt: DateTime! + email: String! + isSeller: Boolean! + name: String! + surname: String! + telegramUsername: String + updatedAt: DateTime! + walletAddress: String! +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 38dea00a..07f8abd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,10 +13,15 @@ "apps/*" ], "dependencies": { - "@stellar/freighter-api": "^3.1.0" + "@nestjs/jwt": "^11.0.0", + "@nestjs/passport": "^11.0.5", + "@stellar/freighter-api": "^3.1.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" }, "devDependencies": { "@biomejs/biome": "1.9.4", + "@types/passport-jwt": "^4.0.1", "lefthook": "^1.8.2", "turbo": "^2.4.1" } @@ -6096,6 +6101,19 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@nestjs/jwt": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@nestjs/jwt/-/jwt-11.0.0.tgz", + "integrity": "sha512-v7YRsW3Xi8HNTsO+jeHSEEqelX37TVWgwt+BcxtkG/OfXJEOs6GZdbdza200d6KqId1pJQZ6UPj1F0M6E+mxaA==", + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "9.0.7", + "jsonwebtoken": "9.0.2" + }, + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" + } + }, "node_modules/@nestjs/mapped-types": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz", @@ -6116,6 +6134,16 @@ } } }, + "node_modules/@nestjs/passport": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", + "integrity": "sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "passport": "^0.5.0 || ^0.6.0 || ^0.7.0" + } + }, "node_modules/@nestjs/platform-express": { "version": "11.0.13", "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.0.13.tgz", @@ -11697,6 +11725,15 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "license": "MIT" }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", + "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lodash": { "version": "4.17.16", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", @@ -11747,6 +11784,38 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, + "node_modules/@types/passport": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.17.tgz", + "integrity": "sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-Y0Ykz6nWP4jpxgEUYq8NoVZeCQPo1ZndJLfapI249g1jHChvRfZRO/LS3tqu26YgAS/laI1qx98sYGz0IalRXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jsonwebtoken": "*", + "@types/passport-strategy": "*" + } + }, + "node_modules/@types/passport-strategy": { + "version": "0.2.38", + "resolved": "https://registry.npmjs.org/@types/passport-strategy/-/passport-strategy-0.2.38.tgz", + "integrity": "sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/passport": "*" + } + }, "node_modules/@types/prop-types": { "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", @@ -14030,6 +14099,12 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -15440,6 +15515,15 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -19234,6 +19318,55 @@ "node": "*" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -19526,6 +19659,18 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, "node_modules/lodash.isequal": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", @@ -19533,6 +19678,30 @@ "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.", "license": "MIT" }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -19547,6 +19716,12 @@ "deprecated": "This package is deprecated. Use destructuring assignment syntax instead.", "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -20765,6 +20940,42 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz", + "integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==", + "license": "MIT", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-jwt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.1.tgz", + "integrity": "sha512-UCKMDYhNuGOBE9/9Ycuoyh7vP6jpeTp/+sfMJl7nLff/t6dps+iaeE0hhNkKN8/HZHcJ7lCdOyDxHdDoxoSvdQ==", + "license": "MIT", + "dependencies": { + "jsonwebtoken": "^9.0.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -20845,6 +21056,11 @@ "node": ">=8" } }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, "node_modules/peek-readable": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.4.2.tgz", diff --git a/package.json b/package.json index 6d003bef..f22ebb8e 100644 --- a/package.json +++ b/package.json @@ -22,10 +22,15 @@ "packageManager": "npm@10.9.2", "devDependencies": { "@biomejs/biome": "1.9.4", + "@types/passport-jwt": "^4.0.1", "lefthook": "^1.8.2", "turbo": "^2.4.1" }, "dependencies": { - "@stellar/freighter-api": "^3.1.0" + "@nestjs/jwt": "^11.0.0", + "@nestjs/passport": "^11.0.5", + "@stellar/freighter-api": "^3.1.0", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1" } }