PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label passport.js. Show all posts
Showing posts with label passport.js. Show all posts

Sunday, November 27, 2022

[FIXED] How to fix unknown authentication strategy "jwt" when I inject another service into user service in nestjs

 November 27, 2022     authentication, module, nestjs, node.js, passport.js     No comments   

Issue

I have a user service that handles registration, login and some other functions. I have been working on the application for sometime now with over 10 modules. But I noticed each time I injected another service and I try to consume any endpoint I get this error "Unknown authentication strategy "jwt". Error on swagger is:-

Internal Server Error
Response body

{
  "statusCode": 500,
  "message": "Internal server error"
}

Once I remove the injected service from the user module, everything is fine again. I have been trying to fix this because I need to use this service inside the user module.

This is the jwt.Strategy.ts

import { Injectable, HttpException, HttpStatus } from "@nestjs/common";
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt, VerifiedCallback } from "passport-jwt";
import { AuthService } from './auth.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(private authService: AuthService) {
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
            ignoreExpiration: false,
            secretOrKey: process.env.SECRETKEY
        });
    }

    async validate(payload: any, done: VerifiedCallback) {
        const user = await this.authService.validateUser(payload);
        try {
            if (user) {
                //return user;
                return done(null, user, payload.iat)
            } else if (user == null) {
                const Terminal = await this.authService.validatePos(payload);
                return done(null, Terminal, payload.iat)
            }
            else {
                return done(
                    //throw new UnauthorizedException();
                    new HttpException('Unauthorised access', HttpStatus.UNAUTHORIZED),
                    false,
                );
            }

        } catch (error) {
            return error;
        }
    }
}

This is the AuthModule

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';
import { UserSchema } from '../user/user.schema';
import { MongooseModule } from '@nestjs/mongoose';
import { JwtStrategy } from './jwt.strategy';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { ApiKeyStrategy } from './apiKey.strategy';
import { PassportModule } from "@nestjs/passport";

@Module({
    imports: [MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
    PassportModule.register({
        secret: "mysec"
    }),
        ActivityLogService],
    providers: [AuthService, UserService, JwtStrategy, ApiKeyStrategy, ActivityLogService],
    exports: [AuthService],
    controllers: []
})
export class AuthModule { }

This is the api.strategy.ts

import { HeaderAPIKeyStrategy } from 'passport-headerapikey';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class ApiKeyStrategy extends PassportStrategy(HeaderAPIKeyStrategy) {
    constructor(private authService: AuthService) {
        super({
            header: 'api_key',
            prefix: ''
        }, true,
            (apikey: string, done: any, req: any, next: () => void) => {
                const checkKey = this.authService.validateApiKey(apikey);
                if (!checkKey) {
                    return done(
                        new HttpException('Unauthorized access, verify the token is correct', HttpStatus.UNAUTHORIZED),
                        false,
                    );
                }
                return done(null, true, next);
            });
    }
}

This is the authService


import { Injectable } from '@nestjs/common';
import { sign } from 'jsonwebtoken';
import { UserService } from '../user/user.service';
import { TerminalService } from '../terminal/terminal.service';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Terminal } from '../terminal/interfaces/terminal.interface';


@Injectable()
export class AuthService {
    constructor(private userService: UserService, @InjectModel('Terminal') private terminalModel: Model<Terminal>,) { }

    //generate token for user
    async signPayLoad(payload: any) {
        return sign(payload, process.env.SECRETKEY, { expiresIn: '1h' });
    }

    //find user with payload
    async validateUser(payload: any) {
        const returnuser = await this.userService.findByPayLoad(payload);
        return returnuser;
    }

    //generate token for Posy
    async signPosPayLoad(payload: any) {
        return sign(payload, process.env.SECRETKEY, { expiresIn: '24h' });
    }

    //find terminal with payload
    async validatePos(payload: any) {
        const { terminalId } = payload;
        const terminal = await this.terminalModel.findById(terminalId);
        return terminal;
    }

    validateApiKey(apiKey: string) {
        const keys = process.env.API_KEYS;
        const apiKeys = keys.split(',');
        return apiKeys.find(key => apiKey === key);
    }
}


This is the user service

import { Injectable, HttpException, HttpStatus, Inject } from '@nestjs/common';
import { User } from './interfaces/user.interface';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { LoginUserDto } from './login-user.dto';
import { ActivityLogService } from '../activity-log/activity-log.service';
import { UpdateUserDTO } from './dtos/update_user.dto';

@Injectable()
export class UserService {
    constructor(@InjectModel('User') private userModel: Model<User>,
        private activityLogService: ActivityLogService,
    ) { }
    
    //Login user
    private users = [
        {
            "userId": 1,
            "name": "John Doe",
            "username": "john",
            "password": "john123"
        },
    ]
    async login(loginDTO: LoginUserDto) {

        const { email, password } = loginDTO;

        return await this.users.find(users => users.username == email)
    }

    async findByPayLoad(payload: any) {
        const { userId } = payload;
        return await this.userModel.findById(userId)
    }
    async getAllUser() {
        return this.users;
    }
}

I cant figure out what I am doing wrong


Solution

Besides the code being difficult to manipulate and determine what's happening, services being in places they shouldn't and re-instantiations of services all over the place, the culprit as to why you are getting the error is simply because you never register the PassportModule from @nestjs/passport


EDIT 1/7/2017

Coming back to this answer about a year and a half later, it looks like the real issue is the use of a REQUEST scoped provider in the strategy. The nest docs explicitly mention this can't be done directly but also have a workaround for it.



Answered By - Jay McDoniel
Answer Checked By - Cary Denson (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, October 20, 2022

[FIXED] How to display Passport.js failure messages to the user

 October 20, 2022     express, javascript, node.js, passport.js     No comments   

Issue

I'm trying to setup a Local Strategy and use failureMessages display authentication errors to the user but I'm unsure the correct way to do this.

The failureMessages are added to the req.session.messages each time a failure occurs but the session.messages are never cleared. Here is the result:

enter image description here

Obviously, the last message is the most recent, but how do I know if the messages are from a current failure or a one that occurred in the past because I only want to display an error message if it is a current failure.

auth.js

  passport.use(new LocalStrategy(
    function(username, password, done) {      
      myDatabase.findOne({ username: username }, function(err, user) {
        if (err) { return done(err); }
        if (!user) { return done(null, false, { message: 'Incorrect username or password.' }); }
        if (!bcrypt.compareSync(password, user.password)) { 
          return done(null, false, { message: 'Incorrect username or password.' }); 
        }
        return done(null, user);
      });
    }
  ));

routes.js

  app.route('/login').post(passport.authenticate('local', { failureRedirect: '/', failureMessage: true }), 
    (req, res) => {
      res.redirect('/profile');
    });

server.js

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: true,
  saveUninitialized: true,
  cookie: { secure: false },
  key: 'express.sid',
  store: store
}));

app.use(passport.initialize());
app.use(passport.session());

Solution

I was able to clear the req.session.messages before sending a new failureMessage by setting the passReqToCallback option. This way we know that any message contained in req.session.messages is a new failure.

  passport.use(new LocalStrategy({ passReqToCallback: true },
    function(req, username, password, done) {      
      myDatabase.findOne({ username: username }, function(err, user) {
        if (err) { return done(err); }
        if (!user) { 
          req.session.messages = [];
          return done(null, false, { message: 'Incorrect username or password.' }); }
        if (!bcrypt.compareSync(password, user.password)) { 
          return done(null, false, { message: 'Incorrect username or password.' }); 
        }
        return done(null, user);
      });
    }
  ));


Answered By - Ryan Dantzler
Answer Checked By - Mary Flores (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

[FIXED] How to use AWS Cognito as a provider in Passport?

 October 20, 2022     amazon-cognito, idp, oauth-2.0, passport.js     No comments   

Issue

I have a Javascript backend (NestJS with Express + Passport).

I would like to outsource the complexity of authentication (e.g. social auth) to Cognito but avoid getting locked in. I was wondering if I can use Cognito as a provider in Passport, similar to social providers (Google, Facebook, etc). That way, I could integrate many providers with the effort of integrating just one. I would still manage user data, authorization, etc in my own app, therefore, if I wanted to in the future, I could implement Google, Facebook, etc. social auth in my own app and get rid of Cognito.

If I understand it correctly this is possible with Auth0.

Ideally, I would like to implement an OAuth flow where the user is redirected to a simple "sign up / log in" Cognito app, logs in, gets redirected to a callback URL in my app where I receive user data. If AWS doesn't host a solution for this, I can also use their UI elements to build & host this app.

If implemented as a provider / strategy, this could be as simple as:

passport.use(new CognitoStrategy({
    key: KEY,
    secret: SECRET,
    callbackURL: "http://www.example.com/auth/cognito/callback"
  },
  function(token, tokenSecret, profile, done) {
      User.findOrCreate({ uuid: profile.id }, function (err, user) {
        return done(err, user);
      });
  }
));

app.get('/auth/cognito', passport.authenticate('cognito'));
app.get('/auth/cognito/callback', 
  passport.authenticate('cognito', { failureRedirect: '/auth/cognito' }),
  function(req, res) {
    res.redirect('/');
  });

Is there a solution for this? Does this make sense in principle? Am I missing any complexity in the many-for-one idea?

Related resources:

  • https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js
  • https://brightinventions.pl/blog/using-cognito-with-nest-js
  • NestJs/Angular/Cognito flow

Solution

It's possible to use both User Pools and Identity Pools via OAuth. Cognito even has a self-hosted UI, with own domain & branding available. Setup steps: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-app-integration.html

I used a generic OAuth2 Passport strategy: https://github.com/jaredhanson/passport-oauth2

Endpoint details: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-userpools-server-contract-reference.html

After the setup, Federated Identities can be set up from the AWS console.

In the end an unbranded screen looks like this:

enter image description here



Answered By - thisismydesign
Answer Checked By - David Marino (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, March 11, 2022

[FIXED] Class App\Http\Controllers\API\UserController does not exist

 March 11, 2022     laravel-5, oauth, oauth-2.0, passport-google-oauth, passport.js     No comments   

Issue

I am Having the issue of not getting token in postman as well as the following problem

ReflectionException …\vendor\laravel\framework\src\Illuminate\Container\Container.php790 user controller does not exist

my route file;

Route::post('login', 'API\UserController@login'); 
Route::post('register', 'API\UserController@register'); 
Route::group(['middleware' => 'auth:api'], function(){
   Route::post('details', 'API\UserController@details'); 
});

My controller file;


    namespace App\Http\Controllers;   
use App\Http\Controllers\Controller; 
use App\User; 
 use Illuminate\Support\Facades\Auth; 
 use Validator; 
use Illuminate\Http\Request;

    class UserController extends Controller {
        //
        public $successStatus = 200;
        /** 
         * login api 
         * 
         * @return \Illuminate\Http\Response 
         */ 
        public function login(){ 
            if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){ 
                $user = Auth::user(); 
                $success['token'] =  $user->createToken('MyApp')-> accessToken; 
                return response()->json(['success' => $success], $this-> successStatus); 
            } 
            else{ 
                return response()->json(['error'=>'Unauthorised'], 401); 
            } 
        }
        /** 
         * Register api 
         * 
         * @return \Illuminate\Http\Response 
         */ 
        public function register(Request $request) 
        { 
            $validator = Validator::make($request->all(), [ 
                'name' => 'required', 
                'email' => 'required|email', 
                'password' => 'required', 
                'c_password' => 'required|same:password', 
            ]); if ($validator->fails()) { 
                return response()->json(['error'=>$validator->errors()], 401);            
            } $input = $request->all(); 
            $input['password'] = bcrypt($input['password']); 
            $user = User::create($input); 
            $success['token'] =  $user->createToken('MyApp')-> accessToken; 
            $success['name'] =  $user->name; return response()->json(['success'=>$success], $this-> successStatus); 
        } 
       /** 
         * details api 
         * 
         * @return \Illuminate\Http\Response 
         */ 
        public function details() 
        { 
            $user = Auth::user(); 
            return response()->json(['success' => $user], $this-> successStatus); 
        }  
} 

How can I Solve this?


Solution

If your controller path is /App/Http/Controllers/API, you need to adjust it's namespace :

namespace App\Http\Controllers\API;

If your controller path is /App/Http/Controllers, you need to adjust your routes:

Route::post('login', 'UserController@login');


Answered By - bgaze
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing