Newsworthy Presidential Mistakes
    Have ideas to improve npm?Join in the discussion! »

    @tomasztrebacz/nest-auth-graphql-redis
    TypeScript icon, indicating that this package has built-in type declarations

    1.6.3 • Public • Published

    Package Logo

    nest-auth-graphql-redis

    Description

    nest-auth-graphql-redis is inseparable part of fox.CMS app. This package handle authentication & authorization using key-value database and add needful layer between app and redis data store. This repository has also the CI/CD pipeline which test & deploy code to NPM and private Github Package Registry.

    Getting started

    • Install package:
    npm install @tomasztrebacz/nest-auth-graphql-redis
    • Create .env file with necessary variables:
    ACCESS_JWT_SECRET=
    ACCESS_JWT_EXP=
    REDIS_HOST=
    REDIS_PORT=
    REDIS_DB=
    REDIS_PASSWORD=
    
    • Create following files in ./config directory:
    // redis.config.ts
    
    export default registerAs("redis", () => ({
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT),
      db: parseInt(process.env.REDIS_DB),
      password: process.env.REDIS_PASSWORD,
    }));
    
    // jwt.config.ts
    
    export default registerAs("jwt", () => ({
      secret: process.env.ACCESS_JWT_SECRET,
      signOptions: { expiresIn: process.env.ACCESS_JWT_EXP },
    }));
    • Import them & package in main module
    imports: [
      ConfigModule.forRoot({
        isGlobal: true,
        load: [redisConfig, jwtConfig],
      }),
      AuthGraphqlRedisModule,
    ];
    • Inject needed parts, for example:
    import { Injectable } from "@nestjs/common";
    import {
      AuthGqlRedisService,
      RedisHandlerService,
    } from "@tomasztrebacz/nest-auth-graphql-redis";
    
    @Injectable()
    export class xyzService {
      constructor(
        private authGqlRedisService: AuthGqlRedisService,
        private redisHandlerService: RedisHandlerService
      ) {}
    }
    • HTTP header
    {
      "Authorization": "Bearer <your_token>"
    }

    Usage

    • Guards & Decorators

      • GqlAuthGuard & Current User
        check if the user is logged & exist in db and get his/her data
      @Query('currentUser')
      @UseGuards(GqlAuthGuard)
      async currentUser(@CurrentUser() user: User) {
        return await this.usersService.findOneById(user.id);
      }
      • RolesGuard & Roles
        check if the user match given role in decorator
      @Query('users')
      @Roles(userRole.ADMIN, userRole.ROOT)
      @UseGuards(GqlAuthGuard, RolesGuard)
      findAll() {
        return this.usersService.findAll();
      }
      • Confirmed
        check if the user is confirmed
      @Query('users')
      @UseGuards(GqlAuthGuard, ConfirmedGuard)
      findAll() {
        return this.usersService.findAll();
      }
      • Auth Decorator - the most readable approach to use this package
        all of the above mentioned guards merged into one
      @Query('users')
      @Auth() // if you want to check also roles, use @Auth('role1', 'role2')
      findAll() {
        return this.usersService.findAll();
      }
      • AccessLevel guard with decorator
        this decorator is useful in scenarios when user with permissions want to change properties of other similar account, e.g, user with admin role provide mutation to API wherein they want to change properties of root user or account with the same role
      @Mutation()
      @AccessLevel()
      async changeRole(
        @Args('changeRoleInput') changeRoleData: ChangeRoleDto,
      ): Promise<boolean> {
        await this.authService.changeRole(changeRoleData);
      
        return true;
      }
    • Enum

      • An important fact is that app is based on the enum describing user roles:
      export enum userRole {
        ROOT = "root",
        ADMIN = "admin",
        USER = "user",
      }
    • Tokens

      • create access token (due to security reasons we reduce payload to user id)
      const accessToken = await this.authGqlRedisService.createDefaultJWT(user.id);
      • create custom tokens with necessary secret, exp date and informations provided in payload (in this example we will create refresh token)
      const payload = {
        id: user.id,
        count: user.count,
      };
      
      const refreshToken = await this.authGqlRedisService.createJWT(
        payload,
        process.env.REFRESH_JWT_SECRET,
        process.env.REFRESH_JWT_EXP
      );
      • verify token
      const { id } = await this.authGqlRedisService.verifyToken(
        exampleToken,
        process.env.EXAMPLE_JWT_SECRET
      );
    • Redis

      • setUser
        comprehensive function for saving new user in database and create/update fields for purposes like reset password, refresh token etc.

        const userProperties = new Map<string, string>([
          ["role", "batman"],
          ["count", "0"],
          ["confirmed", "false"],
          ["confirmtoken", "eyJhbGciOiJ[...]"],
        ]);
        
        await this.redisHandler.setUser(id, userProperties);

        note: all values in redis are stored as strings

      • getFields

        const keys: string[] = ["role", "count"];
        const user = await this.redisHandler.getFields(id, keys);
      • userExists

        await this.redisHandler.userExists(decodedJWT.id);
      • getValue

        const actualRole = await this.redisHandler.getValue(id, "role");
      • deleteField

        await this.redisHandler.deleteField(id, "confirmtoken");
      • deleteUser

        await this.redisHandler.deleteUser(id);

    Real life scenario

    • Visit my profile => fox.CMS repository and see how to seize the opportunities of this package by adding functionalities like reset password by email/phone, confirmation link, refresh token etc.

    Resources

    Note!

    The example featured in the above mentioned post is a bit outdated, but generally this article is a good point to start learning how to create own package.

    License

    Install

    npm i @tomasztrebacz/nest-auth-graphql-redis

    DownloadsWeekly Downloads

    0

    Version

    1.6.3

    License

    MIT

    Unpacked Size

    56.4 kB

    Total Files

    55

    Last publish

    Collaborators

    • avatar