Reputation: 1214
I have a global guard which is use for private routes and implemented with passport-jwt this guard works correctly in REST API but I have some graphql routes and when I send a request it gives the error which logIn is undefined, I found the problem is because of difference of context in graphql is there any way to change graphql excution to http execution context. I have tried many ways but still, there is an error in passport-jwt.
// access token global guard
import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlContextType, GqlExecutionContext } from '@nestjs/graphql';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class AtGuard extends AuthGuard('jwt') {
constructor(private reflector: Reflector) {
super();
}
canActivate(context: ExecutionContext) {
const isPublic = this.reflector.getAllAndOverride('isPublic', [
context.getHandler(),
context.getClass(),
]);
// if public decorator use skip the validation
if (isPublic) return true;
// check context
if (context.getType<GqlContextType>() === 'graphql') {
const ctx = GqlExecutionContext.create(context);
return super.canActivate(ctx);
}
// correctly work for REST API
return super.canActivate(context);
}
}
The errors which I from above code:
another way instead of passing ctx in function I did like this:
if (context.getType<GqlContextType>() === 'graphql') {
const ctx = GqlExecutionContext.create(context);
return super.canActivate(ctx.getContext());
}
but get error which says context.switchToHttp is not a function.
codes in app.module.file
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AuthModule } from './auth/auth.module';
import { GraphQLModule } from '@nestjs/graphql';
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { join } from 'path';
import { TaskModule } from './task/task.module';
import { APP_GUARD } from '@nestjs/core';
import { AtGuard } from './common/guards/at.guard';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
ssl: false,
username: 'root',
password: '',
database: 'coursera',
synchronize: true,
entities: ['dist/**/*.entity{.ts,.js}'],
}),
AuthModule, // REST API BASE
TaskModule, // GraphQl base
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
debug: false,
playground: true,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
}),
],
providers: [
{
provide: APP_GUARD,
useClass: AtGuard,
},
],
})
export class AppModule {}
I expected to get an unauthorized error but I believe there is something wrong with this file. I would appreciate any help. thanks in advance.
Upvotes: 0
Views: 1265
Reputation: 1214
Wow, I solved it. now I use the same guard for both API routes and graphql resolvers, the changes which I did. extract the request and response // app.module
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
debug: false,
playground: true,
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
context: ({ req, res }) => ({
req,
res,
}),
}),
// in guard create my own object and send as params.
// check context
if (context.getType<GqlContextType>() === 'graphql') {
const ctx = GqlExecutionContext.create(context);
const myargs = ctx.getArgByIndex(2);
const customStructure = {
...myargs?.req,
...myargs?.res,
switchToHttp() {
const getRequest = () => {
return myargs?.req;
};
const getResponse = () => {
return myargs?.res;
};
return { getRequest, getResponse };
},
};
return super.canActivate(customStructure);
}
Now I send a graphql request without sending JWT.
Now I send a graphql request with setting JWT in headers.
Upvotes: 0