Skip to content

NestJS module for customizable, multiple OAuth2 clients

License

Notifications You must be signed in to change notification settings

hanchchch/nestjs-oauth2

Repository files navigation

NestJS OAuth2


Features

  • Fully customizable OAuth2 provider configuration.
    • Configure any OAuth2 providers with ease, even for your custom OAuth2 servers.
      {
        name: "spotify",
        authorizeUrl: "https://accounts.spotify.com/authorize",
        accessTokenUrl: "https://accounts.spotify.com/api/token",
        clientId: "<spotifyClientId>",
        clientSecret: "<spotifyClientSecret>",
        scope: "user-read-private user-read-email",
        redirectUri: "http://localhost:4200/oauth/spotify/callback",
      }
  • Injectable OAuth2 service which can be multiplexed to providers.
    • Inject OAuthService to build your own OAuth2 flow like this.
      this.oauthService.with(provider).getAccessToken({ code });
  • Or, just use the built-in OAuth2 flow by injecting OAuthController to your app.
    • and then call GET /oauth/:provider to start OAuth2 flow.

Installation

yarn add nestjs-oauth2

Usage

Please refer to the example for more details.

Settings

OAuthModule.forFeature

Import the module at your app module. Configure the OAuth providers you want to use. Check interface OAuthProvider for more details.

import { OAuthModule, spotifyOptions, googleOptions } from "nestjs-oauth2";

@Module({
  imports: [
    OAuthModule.forFeature({
      providers: [
        {
          ...spotifyOptions,
          clientId: "<spotifyClientId>",
          clientSecret: "<spotifyClientSecret>",
          scope: "user-read-private user-read-email",
          redirectUri: "http://localhost:4200/oauth/spotify/callback",
        },
        {
          ...googleOptions,
          clientId: "<googleClientId>",
          clientSecret: "<googleClientSecret>",
          scope: "https://www.googleapis.com/auth/drive.metadata.readonly",
          redirectUri: "http://localhost:4200/oauth/google/callback",
        },
      ],
    }),
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

OAuthModule.forFeatureAsync

You can also use OAuthModule.forFeatureAsync to configure the providers asynchronously. This way you can hide your client secrets from code. It's recommended to use this method.

import { OAuthModule, spotifyOptions, googleOptions } from "nestjs-oauth2";

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    OAuthModule.forFeatureAsync({
      useFactory: (config: ConfigService) => ({
        providers: [
          {
            ...spotifyOptions,
            clientId: config.get("SPOTIFY_CLIENT_ID"),
            clientSecret: config.get("SPOTIFY_CLIENT_SECRET"),
            scope: "user-read-private user-read-email",
            redirectUri: "http://localhost:4200/oauth/spotify/callback",
          },
          {
            ...googleOptions,
            clientId: config.get("GOOGLE_CLIENT_ID"),
            clientSecret: config.get("GOOGLE_CLIENT_SECRET"),
            scope: "https://www.googleapis.com/auth/drive.metadata.readonly",
            redirectUri: "http://localhost:4200/oauth/google/callback",
          },
        ],
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

Inject OAuthController

Inject OAuthController to your app controller. You can use the built-in OAuth2 flow. In this case, please specify the redirectOrigin (root endpoint of your server e.g. http://localhost:3000/api) instead of redirectUri in the provider settings. OAuthModule will automatically resolves the redirectUri from the redirectOrigin.

import { OAuthModule, OAuthController, googleOptions } from "nestjs-oauth2";

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    OAuthModule.forFeatureAsync({
      useFactory: (config: ConfigService) => ({
        providers: [
          {
            ...googleOptions,
            clientId: config.get("GOOGLE_CLIENT_ID"),
            clientSecret: config.get("GOOGLE_CLIENT_SECRET"),
            scope: "https://www.googleapis.com/auth/drive.metadata.readonly",
            redirectOrigin: "http://localhost:4200",
          },
        ],
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [AppController, OAuthController],
  providers: [],
})
export class AppModule {}

To start OAuth2 flow, just call GET /oauth/:provider.

LOG [RoutesResolver] OAuthController {/oauth}: +3ms
LOG [RouterExplorer] Mapped {/oauth/:provider, GET} route +1ms
LOG [RouterExplorer] Mapped {/oauth/:provider/callback, GET} route +0ms
LOG [RouterExplorer] Mapped {/oauth/:provider/refresh, GET} route +1ms

Inject OAuthService

Inject OAuthService with decorator InjectOAuth. You can use the OAuth2 service to build your own OAuth2 flow.

import { OAuthService, InjectOAuth } from "nestjs-oauth2";

@Controller(`users`)
export class UsersController {
  constructor(@InjectOAuth() private readonly oauthService: OAuthService) {}

  @Get(`oauth/:provider`)
  oauthStart(@Param(`provider`) provider: string, @Res() res: Response) {
    res.redirect(
      this.oauthService.with(provider).getAuthorizeUrl({ state: randomUUID() }),
    );
  }
}

About

NestJS module for customizable, multiple OAuth2 clients

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published