This module turns your [NestJS Application](https://nestjs.com) into an OAuth2 Server. It is based on
npm install nestjs-oauth2-serverThis module turns your NestJS Application into an OAuth2 Server. It is based on
* TypeORM: For entities and database model
* NestJS CQRS Module: For commands and queries
* Passport: For securing routes
``bash`
npm install --save nestjs-oauth2-server
The UserValidatorInterface lets you validate a user using the PasswordGrantStrategy. It is queried in your applicationusername
to validate that the given and password matches with a user in your application's DB.
IMPORTANT: When the user is not found your have to throw an InvalidUserException.
`typescript
import {Injectable} from "@nestjs/common";
import {UserValidatorInterface, UserInterface, InvalidUserException} from "nestjs-oauth2-server";
@Injectable()
export class UserValidator implements UserValidatorInterface {
async validate(username, password): Promise
// check if the user exists with the given username and password
// ...
// or
throw InvalidUserException.withUsernameAndPassword(username, password);
}
}
`
The validate method should return an instance of the UserInterface:
`typescript`
export interface UserInterface {
id: string;
username: string;
email: string;
}
The user interface is then accessible in the payload once connected ot the AccessToken is used.
The UserLoaderInterface lets you load a user from the database when the AccessToken is user specific.
The user is then accessible in the request context of your application.
IMPORTANT: When the user is not found your have to throw an InvalidUserException.
`typescript
import {Injectable} from "@nestjs/common";
import {UserLoaderInterface, UserInterface, InvalidUserException} from "nestjs-oauth2-server";
@Injectable()
export class UserLoader implements UserLoaderInterface {
async load(userId: string): Promise
// Load the user from the database
// ...
// or throw and
throw InvalidUserException.withId(userId);
}
}
`
Import the OAuth2Module into the root AppModule.
`typescript
//app.module.ts
import { Module } from '@nestjs/common';
import { OAuth2Module } from 'nestjs-oauth2-server';
@Module({
imports: [
OAuth2Module.forRoot({
userLoader: new UserLoader(),
userValidator: new UserValidator(),
connection: 'NAME_CONNECTION_PROVIDER'
}),
],
})
export class AppModule {}
`
Of course you can use an async configuration:
`typescript
//app.module.ts
import { Module } from '@nestjs/common';
import { OAuth2Module } from 'nestjs-oauth2-server';
@Module({
imports: [
OAuth2Module.forRootAsync({
useFactory: () => ({
userLoader: new UserLoader(),
userValidator: new UserValidator(),
connection: 'NAME_CONNECTION_PROVIDER'
})
}),
],
})
export class AppModule {}
`
The modules is shipped with a specific controller that lets you expose the oauth2/token endpoint in your application
and use the different implemented strategies accordingly to the request sent.
Used for server-to-server communications.
`bash`
curl -X POST http://localhost:3000/oauth2/token -d '{"grantType":"client_credentials", "clientId":"6ab1cfab-0b3d-418b-8ca2-94d98663fb6f", "clientSecret": "6nV9GGm1pu8OY0HDZ3Y7QsVnxtkb60wu", "scopes": ["app-1"]}'
Used to refresh an existing token
`bash`
curl -X POST http://localhost:3000/oauth2/token -d '{"grantType":"refreshToken", "clientId":"6ab1cfab-0b3d-418b-8ca2-94d98663fb6f", "clientSecret": "6nV9GGm1pu8OY0HDZ3Y7QsVnxtkb60wu", "refreshToken": "6nV9GGm1pu8OY0HDZ3Y7QsVnxtkb6fgqstyudhjqskdqsd"}'
Used to refresh an existing token
`bash`
curl -X POST http://localhost:3000/oauth2/token -d '{"grantType":"password", "clientId":"6ab1cfab-0b3d-418b-8ca2-94d98663fb6f", "clientSecret": "6nV9GGm1pu8OY0HDZ3Y7QsVnxtkb60wu", "username": "j.doe@change.me", "password": "changeme", "scopes": ["app-1"]}'
The module comes with a PassportJS strategy of type http-bearer. You can secure your routes using the passportAuthGuard with the access-token strategy name:
`typescript`
@Controller('oauth2-secured')
export class TestSecuredController {
@Get('me')
@UseGuards(AuthGuard('access-token'))
async auth(): Promise
return {message: 'hello'};
}
}
IMPORTANT: The module comes with entities you have to add the configuration node_modules/*/.entity.jsentitie
to let typeorm scan your entities or add them to the configuration variable in TypeORM.
IMPORTANT: In addition, you should enable the global validation pipe in your NestJS application. In your main.tsuseGlobaPipes
you should use the with the ValidationPipe and the transform options set to true:
`typescript
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), {fallbackOnErrors: true});
app.useGlobalPipes(new ValidationPipe({
transform: true,
}));
await app.listen(3000);
}
bootstrap();
``