GraphQL
GraphQL uses resolvers instead of controllers. The decorators are slightly different, but the concept is the same.
Installation
pnpm add @nestjs-cognito/graphql
Authentication
import { GqlAuthentication, GqlCognitoUser } from '@nestjs-cognito/graphql';
import type { CognitoJwtPayload } from '@nestjs-cognito/core';
@Resolver()
export class UserResolver {
@Query()
@GqlAuthentication()
async me(@GqlCognitoUser() user: CognitoJwtPayload) {
return {
id: user.sub,
username: user.username,
email: user.email
};
}
}
Authorization
import { GqlAuthorization } from '@nestjs-cognito/graphql';
@Resolver()
export class AdminResolver {
@Mutation()
@GqlAuthorization(['admin'])
async adminOperation() {
return { success: true };
}
}
Public Routes
import { GqlPublicRoute } from '@nestjs-cognito/graphql';
@Resolver()
@GqlAuthentication()
export class ProductResolver {
@Query()
@GqlPublicRoute()
async products() {
return [{ id: 1, name: 'Product 1' }];
}
}
Access and ID tokens
import { GqlCognitoIdUser, GqlCognitoAccessUser } from '@nestjs-cognito/graphql';
import type { CognitoIdTokenPayload, CognitoAccessTokenPayload } from '@nestjs-cognito/core';
@Resolver()
export class UserResolver {
@Query()
@GqlAuthentication()
async profile(@GqlCognitoIdUser() user: CognitoIdTokenPayload) {
return {
email: user.email,
groups: user['cognito:groups']
};
}
@Query()
@GqlAuthentication()
async tokenInfo(@GqlCognitoAccessUser() token: CognitoAccessTokenPayload) {
return {
scope: token.scope,
clientId: token.client_id
};
}
}
Subscriptions
Subscriptions use WebSockets. You need to verify the token during connection:
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
import { GraphQLModule } from '@nestjs/graphql';
import { CognitoJwtVerifier } from 'aws-jwt-verify';
@Module({
imports: [
GraphQLModule.forRootAsync<ApolloDriverConfig>({
driver: ApolloDriver,
useFactory: (cognitoVerifier: CognitoJwtVerifier) => ({
autoSchemaFile: true,
subscriptions: {
'graphql-ws': {
onConnect: async (context) => {
const token = context.connectionParams?.authorization?.replace('Bearer ', '');
if (!token) throw new Error('Missing token');
const payload = await cognitoVerifier.verify(token);
return { user: payload };
},
},
},
}),
inject: [CognitoJwtVerifier],
}),
],
})
export class AppModule {}
Protect subscriptions:
@Resolver()
export class NotificationResolver {
@Subscription()
@GqlAuthentication()
notificationAdded(@GqlCognitoUser() user: CognitoJwtPayload) {
return pubSub.asyncIterator(`notifications.${user.sub}`);
}
}
Client side:
import { createClient } from 'graphql-ws';
const wsClient = createClient({
url: 'ws://localhost:3000/graphql',
connectionParams: {
authorization: `Bearer ${accessToken}`,
},
});