nestjs / passport Goto Github PK
View Code? Open in Web Editor NEWPassport module for Nest framework (node.js) ๐
Home Page: https://nestjs.com
License: MIT License
Passport module for Nest framework (node.js) ๐
Home Page: https://nestjs.com
License: MIT License
As user I'd like to use the ExecutionContext to take decisions when doing authn/authz with Passport.
Initially I tried to use multiple guards,
This could be easily done exposing the execution context to this
or somehow passing it to Passport to it makes it available in the validate()
function.
Otherwise, maybe I could be able to override the newly created canActivate
function, precreated by the mixin and add my custom logic underneath....
[ ] Regression
[x] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Currently AuthGuard's method handleRequest
waiting for 3 arguments from authenticate
to callback. But passport passes 4th argument when strategy using fail
method - status code (https://github.com/jaredhanson/passport/blob/master/lib/middleware/authenticate.js - lines 107, 111).
handleRequest should accept 4 arguments
[ ] Regression
[x] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Currently I can see that module attaching strategies to global passport instance. Which preventing me from using different sessions handling and user serialization and deserialization algorithms in different modules.
Passport instance should be defined explicitly for module. For this new Passport()
usually called, which returning independent passport instance with it's own strategies stack.
Creation of modular applications limited by single passport instance for all modules. No way to define more than one serialization strategy.
[ ] Regression
[ ] Bug report
[x ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I'm playing on the sample of nest
, particularly 19-auth-jwt
.
It works well. The secret is not a real one and I got 401 as expected.
The thing is I hope there is some information logged on the console.
Hope there are some error informations.
https://github.com/nestjs/nest/tree/master/sample/19-auth-jwt
After running the server, request http://localhost:3000/profile
.
Hope there's some error information on the console.
An issue has been raised before and closed somehow.
We could overwrite handleRequest
just like others did in #33 (comment).
I think it will be better for us to debug if it's already built-in.
Nest version: 6.10.13
For Tooling issues:
- Node version: XX
- Platform:
Others:
I found this stack overflow question and the solutions seems awful when i believe having a simple accessor on the base PassportStrategy can accommodate a better solution
Would be nice to be able to access passport methods, (I thought this would have been uglier than it ended up being)
export class AuthController {
constructor(private readonly samlStrategy: SamlStrategy) {
}
public logout(@Req() req, @Res() res) {
// Work around
(this.samlStrategy as any).logout(req, function (err, req) {
if (!err) {
res.send('<h1>Logout Failure!!</h1>');
}
});
}
}
https://stackoverflow.com/questions/37990947/access-passport-strategy-from-passport
This is pretty straight forward in JS
var samlStrategy = new saml.Strategy({
callbackUrl: process.env.CALLBACK_URL,
entryPoint: process.env.ENTRY_POINT,
issuer: process.env.ISSUER,
logoutUrl: process.env.LOGOUT_URL
}, function(profile, done) {
var user = profile;
return done(null, user);
});
...
app.get('/logout', function(req, res) {
// samlStrategy.logut uses req.user
console.log(req.user);
// Perform SSO logout with IdP
samlStrategy.logout(req, function(err, request) {
console.log(err);
console.log(request);
if (!err) {
res.redirect(request);
}
});
});
Convenience
I have a /products
api for product list, it can be accessed for guests and logged-in users.
So I need something like a Jwt Guard
but do not force limit this api must provide a jwt token.
If I use @UseGuards(AuthGuard('jwt'))
, the guests cannot access it, but if I remove this guard, how could I access req.user
so that I could return discount price for some users?
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Added http bearer strategy with @nest/passport
as described in the example. It should be protecting the route, by allowing only the http requests with bearer token. If there is no token/invalid token it returns 401. There is no issue in it, but when the token is valid, the validate token returns a user object. The request doesn't make it to the controller. Http request timeouts after few minutes.
Should continue to the controller and return the results of the http end point.
Setups the example.
// http.strategy.ts
import { Strategy } from 'passport-http-bearer';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
@Injectable()
export class HttpStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService ) {
super();
}
async validate(token: string): Promise<any> {
const user = await this.authService.validateToken(token);
if (!user) {
throw new UnauthorizedException();
}
console.log('In strategy');
return user;
}
}
// auth.service.ts
// ...
async validateToken(token: string) {
console.log('Validating user', token);
const user = await this.usersService.findOneByToken(token);
if (user) {
console.log('True');
return user;
}
console.log('False');
return false;
}
// data.controller.ts
// ....
@Get()
@UseGuards(AuthGuard('bearer'))
async view() {
console.log("In controller")
return await this.dataService.findAll();
}
# Console log>
> Validating user 6dafafdadafdafawfsacc9c
> True
> In strategy
As you can see the controller is not printing the In contoller
. Seems like a promise rejection.
Nest version: 5.0.0
For Tooling issues:
- Node version: v8.11.2
- Platform: Linux
Others:
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Cannot use @nestjs/passport because I am getting the following error:
> nest start --watch
[20:10:02] Starting compilation in watch mode...
node_modules/@nestjs/passport/dist/passport/passport.serializer.d.ts:1:27 - error TS2307: Cannot find module 'passport'.
1 import * as passport from 'passport';
~~~~~~~~~~
[20:10:05] Found 1 error. Watching for file changes.
Please check out this repository where you can see the error:
https://github.com/rbutera/nestjs-task-management
try npm run start:dev
and see the error for yourself.
Nest version: 7.x
For Tooling issues:
- Node version: v13.14.0
- Platform: Mac
Others:
Tried using both npm and yarn. same issue.
[ ] Regression
[X] Bug report
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Errors generated by Passport strategies are all substituted with
{
"statusCode": 401,
"error": "Unauthorized"
}
Errors generated by Passport strategies are propagated and displayed to logs with proper Status Codes.
I.E. https://github.com/jaredhanson/passport-local/blob/2bf3939ca369e08a47a28585c2ccfb3cecffeb9c/lib/strategy.js#L75
if (!username || !password) {
# usage of passport.Strategy.fail(challenge: any, status: number): void;
return this.fail({ message: options.badRequestMessage || 'Missing credentials' }, 400);
}
should be returned as:
{
"statusCode": 400,
"error": "Missing credentials"
}
passport-local
example from Nest Documentation: https://docs.nestjs.com/techniques/authentication#implementing-passport-strategiesauth/login
endpoint with incorrect user credentials. You can achieve it by:Content-Type: text/plain
{ "brokenusernamefield": "test", "password": "test"}
Passport strategies provide useful information about Missing Credentials, invalid format of the request, etc. Supressing all this information with 401: Unauthorized
cause problem in debugging sessions. They should be at least logged as errors caught by ExceptionHandler.
Nest version: 6.10.2
Nest passport version: 6.1.1
For Tooling issues:
- Node version: 10.15.3
- Platform: Mac
Others:
It seems the validation of post body runs after auth guards, so I can't validate if some fields valid, how could I validate post body first?
export class LoginDto {
@ApiModelProperty({})
@IsNotEmpty()
mobile: string
@ApiModelProperty()
@IsNotEmpty(})
password: string
}
//....
@Post('login')
@ApiOperation({ title: 'Login' })
@UseGuards(AuthGuard('local'))
async login(@Body() dto: LoginDto, @Req() req) {
const user = req.user
return {
token: this.jwtService.sign(String(user._id)),
};
}
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
AuthGuard not working when it is used in factory.
Conditional AuthGuard should works.
{
provide: APP_GUARD,
// OPTIONAL AUTHGUARD
useFactory: (environment: Environment) => {
if (environment.config.isProduction) {
return AuthGuard('bearer');
} else {
return undefined;
}
},
inject: [Environment],
},
I think we should define options authguards for testing/developing situations.
Nest version: 5.4.0
For Tooling issues:
- Node version: 10.15.0
- Platform: Linux
Hello. Can you please direct me on right way of understanding this error.
[ ] Regression
[X] Bug report
[ ] Feature request
[X] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
import { OIDCStrategy } from 'passport-azure-ad';
import { PassportStrategy } from '@nestjs/passport';
@Injectable()
export class MyStrategy extends PassportStrategy(OIDCStrategy, 'azuread-openidconnect') {
constructor(private readonly authService: AuthService) {
super (
{identityMetadata: config.identityMetadata,...},
(req, iss, sub, profile, jwtClaims, access_token, refresh_token, params, done) => {....}
);
}
}
And i got fail on string where "super (" is written
[Nest] Class constructor MixinStrategy cannot be invoked without 'new'
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Extending PassportStrategy
does not work as expected. In case of extending PassportStrategy(Strategy, 'google')
additional OAuth2 options, respectively provider specific options like e.g. approval_prompt
passed to Superconstructor are NOT applied. So it is not possible to obtain a REFRESH_TOKEN.
Additional, provider specific OAuth2 options can be passed through the Superconstructor and become effective.
My Google OAuth2 strategy implementation:
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-google-oauth20';
import { AuthService, Provider } from './auth.service';
import { ConfigService } from '../config/config.service';
import { User } from '../api/user/user.interface';
@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(configService: ConfigService, private readonly authService: AuthService) {
super({
clientID: configService.get('OAUTH_CLIENT_ID'),
clientSecret: configService.get('OAUTH_CLIENT_SECRET'),
callbackURL: `${configService.baseUrl}/auth/google/callback`,
passReqToCallback: true,
scope: ['email', 'profile'],
// NOT WORKING
approval_prompt: 'force',
access_type: 'offline',
});
}
async validate(request: any, accessToken: string, refreshToken: string, profile: any, done: (err: any, result: any) => void) {
// ...
}
// WORKAROUND: pass options to superclass auth call by overriding superclass method
authorizationParams(options: any): any {
return Object.assign(options, {
approval_prompt: 'force',
access_type: 'offline',
});
}
}
@nestjs/passport: 6.0.0
For Tooling issues:
- Node version: 10.11.0
- Platform: Mac
passport-activedirectory throw an Exception on application start.
When Nest.js application starts, throw the following exception:
TypeError: Class extends value undefined is not a constructor or null
at Object.PassportStrategy
at Object.<anonymous>
at Module._compile (module.js:652:30)
at Module.m._compile
at Module._extensions..js (module.js:663:10)
at Object.require.extensions.(anonymous function) [as .ts]
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
This is my code:
AuthModule
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { AdStrategy } from "./strategies/ad.strategy";
import {PassportModule} from '@nestjs/passport';
@Module({
imports: [PassportModule],
controllers: [AuthController],
providers: [AuthService, AdStrategy]
})
export class AuthModule {
}
AdStrategy (strategies/ad.strategy.ts)
import {Strategy} from "passport-activedirectory";
import {AuthService} from "../auth.service";
import {PassportStrategy} from '@nestjs/passport';
import {Injectable} from "@nestjs/common";
@Injectable()
export class AdStrategy extends PassportStrategy(Strategy, 'activedirectory') {
constructor(private readonly authService: AuthService) {
super({
integrated: false,
ldap: {
url: 'ldap://my.domain.com',
baseDN: 'DC=my,DC=domain,DC=com',
username: '[email protected]',
password: 'readuserspassword'
}
});
}
async validate(profile, ad): Promise<any> {
// TODO
const user = this.authService.validateUser(username, password);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
I expect the application run without exception.
Nest version: 6.0.0
For Tooling issues:
[ ] Regression
[X] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I don't know if it's a bug or of it's expected to work in this way.
I would like to check role coming inside jwt token in my auth guard, in canActivate method.
I've seen this approach in Guards example in documentation.
At this moment, payload seems to be decoded in validate method, in JWTStrategy class, but this happens after canActivate.
What would be the best approach to handle this?
If canActivate is not the right place to check this, where is it?
Receive decoded token in canActivate
Dependencies related with this:
@nest/passport
@nest/jwt
When server receives request, the flow is:
Having a useful canActivate method.
Nest version: 5.3.5
For Tooling issues:
- Node version: 10.0.0
- Platform: Mac
Others:
I am using the AuthGuard in combination with Passport to validate the api-key header using the passport-apikey package. When there is no api key present in the header, the package returns a BadRequestError, which is passed in the info property in the handleRequest
method in the authguard. This argument is completely ignored, only when an error is returned as the first argument will it be thrown.
The only way I see is checking for an error in the info argument:
handleRequest(err, user, info, context) {
if (err) {
throw err;
} else if (info instanceof Error) {
throw info;
} else if (!user) {
throw new UnauthorizedException();
}
return user;
}
The failure(s) returned by the passport-apikey package, which uses the fail
method of the Passport Strategy class to record the failure, are ignored by the AuthGuard and therefore the generic UnauthorizedException is always returned, which doesn't make sense if you are missing an API key.
When using passport-http
to provide some Basic
authentication, I don't receive the Realm in the failure response and therefore I'm not prompted by the browser.
It is setting the realm as the failure reason. Because we ignore the info
argument then it's never sent back to the client.
Any idea on how you'd see this working? I'm happy to do the PR.
I can not make passport local work.
the login work , and return the user, but getUserAuthenticated retrun undefined.
the project.
@Post('login')
@UseGuards(AuthGuard('local'))
@HttpCode(HttpStatus.OK)
async login(@Body() user: LoginRequest, @Req() req): Promise<User> {
// this is work fine.
return req.user;
}
@Get('getUserAuthenticated')
async getUserAuthenticated(@Req() req) {
// here req.user is undefined
return {user:req.user};
}
[ ] Regression
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
With the current version, it seems, to use passport with cookies sessions, we have to declare its middlewares manually in main.js
, like :
app.use(session({
secret: 'a secret',
name: 'abcd',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
This approach prevents me to use Nest injection, so it prevents me to use my ConfigurationModule & TypeORMModule for example to configure the session store.
So I would like this nestjs/passport module register passport.initialize()
and passport.session()
automatically.
I've tried, by "monkey-patching" the library to add this configure
implementation in PassportModule code :
configure(consumer) {
const DEFAULT_ROUTES = [{ path: '*', method: common_1.RequestMethod.ALL }];
const middlewares = [
passport.initialize(),
passport.session(),
]
consumer
.apply(...middlewares)
.forRoutes(...DEFAULT_ROUTES)
}
But maybe it should be "configurable", maybe it could depend on the session
options flag.
But I don't know how to implement such a case in practice. I wonder if we have to implement forRoot / forRootAsync on PassportModule to do it this way ?
The following repository provide a good base to reproduce the case : https://github.com/Nabellaleen/hello-graphql-session-nestjs
In practice, this change is motivated by this discussion : iamolegga/nestjs-session#181
- @nestjs/common: 7.0.5
For Tooling issues:
- Node version: v10.15.3
- Platform: Linux
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
When I try to use passport-facebook-token
library with this library I am getting this error:
TypeError: Class extends value undefined is not a constructor or null
/home/mrav/projects/gitdiagram-server/node_modules/@nestjs/passport/dist/passport/passport.strategy.js:13 class MixinStrategy extends Strategy {
I am trying to use given library like this:
import Strategy from "passport-facebook-token";
import { Injectable } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
@Injectable()
export class GitHubStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
clientID: "client_id",
clientSecret: "client_secret",
passReqToCallback: true
});
}
async validate(
request: any,
accessToken: string,
refreshToken: string,
profile,
next: Function
) {
try {
console.log(profile);
next(null, profile);
} catch (err) {
console.log(err);
next(err, null);
}
}
}
I think that main problem is that passport-facebook-token
is creating strategy by extending OAuth2Strategy
and other libraries like passport-facebook
are using util.inherits
method. In node documentation util.inherits
is deprecated.
As I can see nestjs/passport
library is expecting Strategy to be function, link to source code.
Why I want to use passport-facebook-token
strategy, because I want to implement implicit grant flow for my SPA application.
I have found one more library that is creating strategy in the same way:
It would be nice if library would support strategies that are created by extending OAuth2Strategy
.
Nest version: 6.0.0
For Tooling issues:
- Node version: v8.15.0
- Platform: Ubuntu
Others:
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Though Passport allow for an array of string to be passed as an argument for the declared strategies, AuthGuard, and defaultStrategy does not.
From nestjs/nest#2116:
Be able to specifify multiple authtentication middlewares | authGuards to protect the same resources, let's say for example if a haver this controller but want to be able to authenticate for twitter and google.
In this case the controller method should be accesible whether im logged in via twitter or google
@UseGuards(AuthGuard(['google', 'twitter']))
~~~~~~~~~~~~~~~~~~~~~ // <-- Argument of type 'string[]' is not assignable to parameter of type 'string'.
async sayHello(){
return "hello"
}
This module should allow to interact with Passport as if we were interacting with Passport directly.
Nest Passport version: 6.0.0
Others:
[ ] Regression
[ ] Bug report
[*] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Unable to configure PassportStrategy
per request
I want to be able to set custom PassportStrategy settings per request.
My use-case: The app is deployed on dynamic, multiple domains,
And i want to be able to set the callbackURL for oauth providers by the request.host, protocol, etc.
@Injectable({
scope: Scope.REQUEST,
})
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(
@Inject(REQUEST) private readonly request: import("express").Request,
private readonly authService: AuthService,
) {
super({
clientID: 'CLIENT_ID', // <- Replace this with your client id
clientSecret: 'CLIENT_SECRET', // <- Replace this with your client secret
callbackURL: `${request.protocol}://${request.host}/auth/google/callback`,
passReqToCallback: true,
scope: ['profile'],
});
}
This code doesn't work, i get unknown strategy "google",
Because the strategies must be not Scope.REQUEST
How I can use nest.js with passport-steam authentication? Where I should put passport.use, auth routes, etc.? Is there any examples of how to use nest.js with other sites authentication (except Auth0)
[ ] Regression
[ ] Bug report
[ ] Feature request
[X] Documentation issue or request
[ ] Support request
I am using AuthGuard, in the Docs you say that you can call it like this @UseGuards(AuthGuard('jwt')) and the that AuthGuard accepts a second argument, options object that you are able to pass in order to determine the passport behavior.
The idea behind this is that I can make a call like this @UseGuards(AuthGuard('jwt',{roles: 'admin'})) so that I can give access only if the jwt has the 'admin' role. However, it is impossible to access these options from the validate method in the JwtStrategy.
This is my code, extracted from the 19-auth project:
jwt.strategy.ts
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: JwtPayload, done: Function) {
const user = await this.authService.validateUser(payload);
// I want to use the options here in order to check the roles
if (!user) {
return done(new UnauthorizedException(), false);
}
done(null, user);
}
}
auth.controller.ts
@Get('data')
@UseGuards(AuthGuard('jwt',{roles: 'admin'}))
findAll() {
return 'ACK';
}
How can I get these options from there?
Thank you in advance.
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
export class JwtStrategy extends PassportStrategy(Strategy) {
...
async validate(payload: JwtPayload, done: Function) {
if (!payload) {
return done(new UnauthorizedException(), false)
}
done(null, payload, 'xxxxxxxxx')
}
}
request:
{
...
authInfo: undefined,
user: { id: 123, username: 'admin', iat: 1541730420, exp: 1541734020 } }
}
@nestjs/passport/dist/auth.guard.js
const createPassportContext = (request, response) => (type, options, callback) => new Promise((resolve, reject) => passport.authenticate(type, options, (err, user, info) => {
try {
request.authInfo = info;
console.log(request.authInfo:${request.authInfo}
)
...
it will be executed twice:
request.authInfo:xxxxxxxxx
request.authInfo:undefined
{
...
authInfo: 'xxxxxxxxx',
user: { id: 123, username: 'admin', iat: 1541730420, exp: 1541734020 } }
}
Nest version: 5.4.0
For Tooling issues:
- Node version: 8.12.0
- Platform: Windows
Others:
Since validate function is being considered as promise don't send callback function of passport. Because callback function is called from after validate function completed Ref: passport.strategy.ts
.
Moreover, I don't understand how to pass info
(3rd parameter of callback). Since its being used for authInfo
field of request object in auth.guard.ts
file.
passport/lib/passport/passport.strategy.ts
Lines 14 to 24 in 8acdc04
Lines 82 to 89 in 8acdc04
When using the AuthGuard
on a controller it works fine, but when used on a GraphQL query or mutation it shows the following error in terminal:
Probably graphql is waiting for the return of a false boolean in failure case, but authentication returns a http exception
This is my example
The code below emits an error which says the package has no exported member BearerStragety
.
It exports Strategy
instead.
import { BearerStrategy } from 'passport-http-bearer';
Class declaration also emits errors.
export class HttpStrategy extends PassportStrategy(Stragety) {
[ts] 'extends' clause of exported class 'HttpStrategy' has or is using private name 'AbstractStrategy'.
[ts] 'extends' clause of exported class 'HttpStrategy' has or is using private name 'Type'.
package.json
"@nestjs/passport": "^1.0.5",
using --declaration
flag
[ ] Regression
[ ] Bug report
[X ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I have to duplicate code to specify a Passport type, the classes contain the exact same code. except for the below
export class AzureLoginGuard extends AuthGuard('azure') {}
export class SamlLoginGuard extends AuthGuard('saml') {}
export class AzureLoginCallbackGuard extends AuthGuard('azure') {}
export class SamlLoginCallbackGuard extends AuthGuard('saml') {}
It would be nice to be able to pass the type into an common AuthGuard that will then propigate up to passport
@UseGuards(LoginGuard('azure'))
@UseGuards(LoginGuard('saml'))
Im using sessions for example, and i need to do :
await super.canActivate(context); // throws Unauthorized
super.logIn(req);
if i wanted to have a facebook, twitter, google i would need to have 3 classes to do the same thing
Nest version: 6.5.0
For Tooling issues:
- Node version: XX v12.3.1
- Platform: WIndows
Others:
[ ] Regression
[x] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
I am using guards in a Gateway, and together with that, the passport jwt strategy from the documentation example.
Using a custom extractor I am able to send the jwt as a query parameter with the initial socket request to be authenticated:
const fromSocketQueryParameter = (request) => {
const rawUrl = request.url ||ย request.handshake.url;
let token = null;
const parsed_url = url.parse(rawUrl, true);
if (parsed_url.query && Object.prototype.hasOwnProperty.call(parsed_url.query, 'token')) {
token = parsed_url.query['token'];
}
return token;
}
There is a problem when the token has expired which is that UnauthorizedException is thrown within @nestjs/passport/options.js and that one is extending HttpException. This causes an internal server error to be visible to the client because in @nestjs/websockets all errors that are not WsExceptions is returning internal server error.
Is it possible to override or catch the error thrown when the jwt token is not valid? I would like to throw a WsException instead.
It would also be useful if this could be handled in the validate action within the strategy, but that one seems to be called after the actual verification of the jwt token, meaning that the error has already been thrown.
It is not possible to handle expired access when using sockets, which it should be.
Nest version: 5.1.0
For Tooling issues:
- Node version: 10.6.0
- Platform: Mac, Ubuntu
Others:
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
If I add 3rd argument to callback e.g., payload
I should be able to retrieve it via req.authInfo
in controller. Currently I am getting user
as expected but authInfo
as undefined
.
I should be able to retrieve both user
and authInfo
from request
in the Controller
import { ExtractJwt, Strategy } from 'passport-jwt';
import { AuthService } from './auth.service';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtPayload } from './interfaces/jwt-payload.interface';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: JwtPayload, done: Function) {
const user = await this.authService.validateUser(payload);
if (!user) {
return done(new UnauthorizedException(), false);
}
done(null, user, payload);
}
}
async findAll(@Req() req): Promise<Project[]> {
console.log(req.user)
console.log(req.authInfo)
return this.projectService.findAll();
}
I want to keep user
and optional info
separate as intended by passport
for interoperability with other libraries and consistency.
[System Information]
OS Version : macOS High Sierra
NodeJS Version : v10.5.0
NPM Version : 6.1.0
[Nest Information]
microservices version : 5.1.0
websockets version : 5.1.0
passport version : 1.1.0
typeorm version : 5.0.2
common version : 5.1.0
core version : 5.1.0
Nest version: X.Y.Z
For Tooling issues:
- Node version: XX
- Platform:
Others:
Hallo,
when using the guard to protect the login-route, the user is correctly set at the request-object when the user passes the right credentials (I am using the LocalStrategy). So I though, everything would be alright...
but the user is not persisted to the session.
By debugging I found out that the AuthGuard doesn't call Passport's logIn()-function and therefore the user is only set to the request, but not persisted to the session. I believe this is quite an unexpected behavior for most users because it is different to the default way that Passport works.
In my opinion this should either be fixed or at least documented.
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
npm install @nestjs/passport
import { PassportStrategy } from '@nestjs/passport';
[ts]
Could not find a declaration file for module '@nestjs/passport'.
...@nestjs/passport/index.js' implicitly has an 'any' type.
"@nestjs/passport": "^1.0.2",
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Currently AuthGuard's method handleRequest is using 3 arguments, but the order of them are different between the callback creation (L46) and the execution (L85).
callback(err, user, info)
(err, info, user) => this.handleRequest(err, info, user)
There is no bug here because it just receive and pass the arguments, but it's confusing and could cause issues.
Expected behavior
The callback creation should be (err, user, info) => this.handleRequest(err, user, info)
Line 86 in e9d1766
const createPassportContext = (request, response) => (type, options, callback) => new Promise((resolve, reject) => passport.authenticate(type, options, (err, user, info) => {
try {
request.authInfo = info;
return resolve(callback(err, user, info));
}
catch (err) {
reject(err);
}
})(request, response, resolve));
Here authenticate call "next" to trigger an error, but we provide "resolve" as "next" parameter. Shouldn't error call reject?
At least for me it's an issue. I follow the tutorial https://docs.nestjs.com/techniques/authentication and I don't get the 401 Unauthorized.
By default, if authentication fails, the AuthGuard will respond with a generic unauthorized error message.
But In some cases the built-in options are not sufficient to handle an authentication request.
Then it should be possible provide a Custom Callback to allow the application to handle success or failure.
For example:
const CustomCallback = (err, user, info) => {
let message
if (err) {
return Promise.reject(err || new UnauthorizedException());
} else if (typeof info != 'undefined' || !user) {
switch (info.message) {
case 'No auth token':
case 'invalid signature':
case 'jwt malformed':
case 'invalid token':
message = "You must provide a valid authenticated access token"
break
case 'jwt expired':
message = "Your session has expired. Please log in again"
break
}
return Promise.reject(new UnauthorizedException(message))
}
Promise.resolve(user);
}
@Get('data')
@UseGuards(AuthGuard('jwt', { session: false }, CustomCallback))
getSensitiveData() {
// this route is restricted
}
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
The strategy delivered by openid-client
does not have access to all params such as userinfo
-object because the library openid-client
does a check on the number of parameters sent into the callback function. Because the callback function uses destructuring of the params, the number of parameters equals 0 and thus the userinfo
-object of openid-client
is not appended in the parameters. This is very unexpected behavior, as it "works" when putting the verify function directly in the constructor super call where the parameters are declared separately (tokenset, userinfo, done) => {}
. This is unwanted as I would really like to stay idiomatic and use the framework as it is meant to be used.
Ideally, I would be able to declare the params (tokenset, userinfo) in the validate function, as I am trying to do, and still have the openid-client
correctly interpret the correct amount of parameters.
In the below screenshot we see the check that adds the userinfo object if the length of the parameters of the verify/validate function is large enough. In our case when using the Nest PassportStrategy validate function, the destructuring of params results in this._verify.length // => 0
.
Here the destructuring happens:
PassportModule should be able to support openid-client
(OpenID Connect) which covers strategies for a wide range of IdPs such as Okta and OneLogin.
Nest version: 6.10.1
[ ] Regression
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Validate jwt token using Azure AD.
Nest version: X.Y.Z
For Tooling issues:
- Node version: XX
- Platform:
Others:
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
After update to 5.0.1 I get strange error when use @UseGuards(AuthGuard('bearer'))
{ Error: Pool is closed.
at Pool.Object.<anonymous>.Pool.getConnection (C:\www\gmc\back\node_modules\mysql\lib\Pool.js:25:15)
at C:\www\gmc\back\src\driver\mysql\MysqlDriver.ts:566:27
at new Promise (<anonymous>)
at MysqlDriver.Object.<anonymous>.MysqlDriver.obtainMasterConnection (C:\www\gmc\back\src\driver\mysql\MysqlDriver.ts:559:16)
at MysqlQueryRunner.Object.<anonymous>.MysqlQueryRunner.connect (C:\www\gmc\back\src\driver\mysql\MysqlQueryRunner.ts:79:58)
at MysqlQueryRunner.<anonymous> (C:\www\gmc\back\src\driver\mysql\MysqlQueryRunner.ts:143:55)
at step (C:\www\gmc\back\node_modules\typeorm\driver\mysql\MysqlQueryRunner.js:42:23)
at Object.next (C:\www\gmc\back\node_modules\typeorm\driver\mysql\MysqlQueryRunner.js:23:53)
at C:\www\gmc\back\node_modules\typeorm\driver\mysql\MysqlQueryRunner.js:17:71
at new Promise (<anonymous>) code: 'POOL_CLOSED' }
Code of my BearerStrategy
:
import { Strategy } from 'passport-http-bearer';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { OauthClientTokenService } from './client/token/oauth-client-token.service';
import { PassportStrategy } from '@nestjs/passport';
@Injectable()
export class BearerStrategy extends PassportStrategy(Strategy) {
constructor(private readonly clientTokenService: OauthClientTokenService) {
super();
}
validate(token: any, done) {
this.clientTokenService.findByAccessToken(token).then(async (clientToken) => {
if (!!clientToken) {
const user = await clientToken.user;
done(null, user);
} else {
done(new UnauthorizedException(), false);
}
}).catch((error) => {
console.log(error);
done(error, false);
});
}
}
Method findByAccessToken
correctly returns token-entity. But querying of user
causes error.
Nest version: 5.3.0
For Tooling issues:
- Node version: 10.1.0
- Platform: Windows
[x] Regression
[ ] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Install the package
npm install @nestjs/passport
Importing something from the package results in an error.
import { PassportStrategy } from '@nestjs/passport';
[nodemon] 1.18.3
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: /usr/src/api/src/**/*
[nodemon] starting `ts-node -r tsconfig-paths/register src/main.ts`
Error: Cannot find module './dist'
"@nestjs/passport": "^1.1.0",
Specifying ~1.0.11
resolves the issue. Looks like a re-occurrence of #2
Following the NestJS JWT auth tutorial from the documentation I noticed that the UnauthorizedException is handled "internally". Instead of printing
You'll get {"statusCode":500,"message":"Internal server error"}
along with this log message [Nest] #14156 14:59:46 - error: [root] { statusCode: 401, error: 'Unauthorized' }
It should print that error as JSON response along with the right http response code right?
[x] Feature request
[x] Documentation issue or request
From my understanding:
'passport' is highly reliant on 'express'. Therefore 'nestjs/passport' does not support 'fastify' or other httpadapters one might use.
I would just like it to be clarified to me, and if true, to be 'noted' in docs.
TSError: โจฏ Unable to compile TypeScript src/auth/jwt.strategy.ts (10,5): Call target does not contain any signatures. (2346)
src/auth/jwt.strategy.ts super() constructor extending from PassportStrategy
does not contain any signatures:
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
Nest version: 5.0.0-rc.3
@nestjs/passport: v1.0.9
TypeScript: 2.8.3
For Tooling issues:
- Node version: 10.0.0
- Platform: Linux
[ ] Regression
[X] Bug report
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
This is a bug report and/or feature request -- the behavior is necessary for proper authentication error handling.
Issue: There's no way to remove the session if the JWT token is malformed. Passport de-serialization just fails, and there's no access to the request and response objects in context.
Related to #136 -- however, without the response context, it may not be possible to handle all session operations in many standard workflows.
Deserialization errors could be caught, and handled (with the request / response context). Without this, the session can't be fixed.
[x] Regression
[] Bug report
[] Feature request
[ ] Documentation issue or request
I'm unable to replicate documented nestjs authentication example code because the PassportModule does not exist.
Example code should work as expected with the PassportModule exposed.
Unable to import PassportModule from @nestjs/passport
I need to implement jwt based authentication
Nest version: 5.0.0
Nest Passport version: 1.1.0
For Tooling issues:
- Node version: 10.6.0
- Platform: Windows
Others:
[ ] Regression
[ x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
When passport-http-strategy is used, nest does not set WWW-Authenticate header https://tools.ietf.org/html/rfc6750, passport strategy currently prepares correct challenge, AuthGuard exposes it on req.authInfo, only thing missing is proper WWW-Authenticate header.
Response WWW-Authenticate header should be set according to challenge produced by passport
https://tools.ietf.org/html/rfc6750
nestjs/passport version: 7.0.0
For Tooling issues:
- Node version: 10.16.3
- Platform: Windows
[ ] Regression
[ ] Bug report
[X] Feature request
[ ] Documentation issue or request
[ ] Support request
If we want to override the strategy callback function, we must provide the custom function each time we use AuthGuard.
@UseGuards(AuthGuard('jwt', { callback: customCallback }))
It would be more elegant to set the callback function once in the strategy class.
export declare abstract class AbstractStrategy {
callback: (err, user, info) => {
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
abstract validate(...args: any[]): any;
}
Normally, we use the same function for the entire application.
I spent the last couple of days trying to debug why the passport module does not work. Turns out the package doesn't show thrown errors.
For example, jsonwebtoken threw an invalid signature
error but Nestjs does not log it on the console.
Expected behaviour should be logging the error to console and throw a 500 Internal Server error to the user.
[ ] Regression
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Hello I have submitted this issue on stackoverflow and I have not been able to get any solutions for days now. Kindly assist.
[Issue](https://stackoverflow.com/questions/55820591/nestjs-jwt-authentication-returns-401)
[ ] Regression
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.
Looking at the example here, it looks pretty straight forward, but I'll like to know how best it is to implement OAuth2 with NestJs using oauth2orize.
I'm pretty new to NestJs Ecosystems.
I also had a look at https://docs.nestjs.com/techniques/authentication, this helpful in setting up strategies but I'm concerned about the oauth2orize.createServer()
implementation.
Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.