npm package: @rockyatoyan/nest-oauth
Description: Universal OAuth module for NestJS that allows you to easily connect OAuth providers (Google, GitHub, etc.) with a single API, minimal configuration, and convenient decorators.
Author: Robert Atoyan
Latest version: 0.0.9

# @rockyatoyan/nest-oauth

Universal OAuth module for **NestJS** that allows you to easily connect OAuth providers (Google, GitHub, etc.) with a single API, minimal configuration, and convenient decorators.

---

## Features

- 🔐 Support for multiple OAuth providers
- 🧩 Simple expansion through custom providers
- ⚙️ Asynchronous module registration
- 🪝 Ready-made decorators for authorization URLs and callbacks
- 📦 Easy integration with `@nestjs/config`

---

## Installation

```bash
npm i @rockyatoyan/nest-oauth
```

## Module registration

```typescript
import { ProviderModule } from '@rockyatoyan/nest-oauth';
import { ConfigModule, ConfigService } from '@nestjs/config';

ProviderModule.registerAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (configService: ConfigService) => {
    return {
      baseUrl: configService.getOrThrow<string>(envNames.DOMAIN),
      providers: [
        new GoogleProvider({
          clientId: configService.getOrThrow<string>(envNames.OAUTH_GOOGLE_CLIENT_ID),
          clientSecret: configService.getOrThrow<string>(envNames.OAUTH_GOOGLE_CLIENT_SECRET),
        }),
        new GithubProvider({
          clientId: configService.getOrThrow<string>(envNames.OAUTH_GITHUB_CLIENT_ID),
          clientSecret: configService.getOrThrow<string>(envNames.OAUTH_GITHUB_CLIENT_SECRET),
        }),
      ],
    };
  },
});
```

## Creating OAuth providers

```typescript
import { BaseProvider, ProviderInstanceOptions, ExtractUserResponse } from '@rockyatoyan/nest-oauth';

interface GithubUserInfo {
  id: number;
  name: string;
  avatar_url: string;
  email: string;
}

export class GithubProvider extends BaseProvider {
  constructor(options: ProviderInstanceOptions) {
    super({
      name: 'github',
      clientId: options.clientId,
      clientSecret: options.clientSecret,
      scopes: ['user'],
      authUrl: 'https://github.com/login/oauth/authorize',
      tokensUrl: 'https://github.com/login/oauth/access_token',
      userInfoUrl: 'https://api.github.com/user',
    });
  }

  override extractUserInfo(data: GithubUserInfo): ExtractUserResponse {
    return {
      id: String(data.id),
      avatarUrl: data.avatar_url,
      email: data.email,
      provider: this.options.name,
    };
  }
}
```

## Usage

### Getting the authorization URL

```typescript
@OAuthUrl()
@Get('oauth/:provider/url')
async getOAuthProviderUrl() {}
```

### OAuth callback

```typescript
@OAuthCallback()
@Get('oauth/:provider/callback')
async oauthCallback(
  @Req() req: Request,
  @Res({ passthrough: true }) res: Response,
) {
  try {
    await this.authService.loginWithOAuth(req, req.providerInfo!);
  } catch (error) {
    return res.redirect(
      this.configService.get(envNames.CLIENT_ORIGIN) +
        '/auth/login?error=true',
    );
  }

  return res.redirect(
    this.configService.get(envNames.CLIENT_ORIGIN) + '/dashboard/profile',
  );
}
```