What is the best pattern for API Gateway Service and Authentication Service in microservice design

557 views Asked by At

I am building a microservice project, with two of the services are:

  • API Gateway: for routing to suitable service.
  • Authentication service: for authenticating user credentials/user's tokens.

The Authentication service is built by NestJS with TCP protocol.

Forcase login:

  • HTTP request from client to API Gateway. API Gateway send to Authentication service const oAuthenticatedUser: LoginUserResponseDto = await this.authMicroServiceClient.send('login', loginRequest).toPromise() for validating the email and password. It will return UserInfo (name, access_token and regresh_token) if user's credentials are correct.

For case: create-post

  • HTTP request from client to API Gateway with access_token in header. Before calling to post-service for executing post-creation, API Gateway call Authentication service for verifying the token by const authenReponse = await this.authMicroServiceClient.send('verify_access_token', { token: access_token }).toPromise();

My pain point: I cannot use Passport strategy in Authentication service for implementing common verifying token. Because the request to Authentication Service is now not a normal HTTP request. Then these current code are not able to use:

import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { TJwtPayload } from '../../types/auth/jwt-payload.type';
import { UserSimpleDTO } from '@modules/user/dto';
import { ConfigService } from '@nestjs/config'
import { TokenService } from '@app/shared/services'

/**
 * Powered Thuan
 * @author thuan.nguyen
 * @namespace auth
 * @classname JwtAccessTokenStrategy
 **/
@Injectable()
export class JwtAccessTokenStrategy extends PassportStrategy(Strategy, 'jwt-access-token') {
    constructor(private readonly tokenService: TokenService, configService: ConfigService) {
        super({
            jwtFromRequest: ExtractJwt.fromExtractors([
                ExtractJwt.fromAuthHeaderAsBearerToken(),
            ]),
            ignoreExpiration: true,
            secretOrKey: configService.get("JWT_ACCESS_SECRET"),
        });
    }

    async validate(payload: TJwtPayload): Promise<UserSimpleDTO> {
        const user = await this.tokenService.validatePayload(payload);
        if (!user) {
            throw new UnauthorizedException('Cannot find user via payload');
        }
        return user;
    }
} 

And

import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UserService } from '../user/user.service';
import { UserLoginReqDTO } from '@modules/user/dto';

/**
 * Powered by Thuan
 * @author thuan.nguyen
 * @namespace auth
 * @classname LocalStrategy
 **/
@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
    constructor(
        private userService: UserService,
    ) {
        super({ usernameField: 'email' });
    }

    async validate(email: string, password: string): Promise<UserLoginReqDTO> {
        const user: UserLoginReqDTO = await this.userService.getUserIfPasswordMatches(email, password);
        if (!user) {
            throw new UnauthorizedException();
        }
        return user;
    }
}

My question is: My design is a good one or not. I would like to know the better design. And How to use above code with requests transfered by TCP protocol.

Thank you!

0

There are 0 answers