npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@elchinabilov/nestjs-signin

v1.0.1

Published

A NestJS module for social sign-in authentication with multiple providers (Google, Apple). Verify ID tokens, extract user profiles, and integrate social login into your NestJS application with ease.

Readme

@elchinabilov/nestjs-signin

A powerful and extensible NestJS module for social sign-in authentication. Verify ID tokens from multiple providers (Google, Apple) and get normalized user profiles with a single, unified API.

Features

  • Google Sign-In - Verify Google ID tokens using the official google-auth-library
  • Apple Sign-In - Verify Apple ID tokens with JWKS public key validation
  • Unified API - Single verifyToken() method for all providers
  • Normalized User Profile - Consistent SignInUser interface across all providers
  • Dynamic Module - Supports both forRoot() and forRootAsync() patterns
  • Global Module - Register once, use anywhere in your application
  • Type-Safe - Full TypeScript support with comprehensive type definitions
  • Custom Exceptions - Descriptive error types for different failure scenarios
  • Built-in DTO - Ready-to-use VerifyTokenDto with class-validator decorators
  • Extensible - Easy to add new providers in the future

Installation

npm install @elchinabilov/nestjs-signin

Peer Dependencies

Make sure you have the following packages installed in your NestJS project:

npm install @nestjs/common @nestjs/core reflect-metadata rxjs

Optional (for DTO validation):

npm install class-validator class-transformer

Quick Start

1. Register the Module

import { Module } from '@nestjs/common';
import { SignInModule } from '@elchinabilov/nestjs-signin';

@Module({
  imports: [
    SignInModule.forRoot({
      google: {
        clientIds: [
          'YOUR_GOOGLE_WEB_CLIENT_ID',
          'YOUR_GOOGLE_IOS_CLIENT_ID',
          'YOUR_GOOGLE_ANDROID_CLIENT_ID',
        ],
      },
      apple: {
        clientIds: ['YOUR_APPLE_SERVICE_ID'],
      },
    }),
  ],
})
export class AppModule {}

2. Use the Service

import { Controller, Post, Body } from '@nestjs/common';
import {
  SignInService,
  SignInProvider,
  SignInUser,
  VerifyTokenDto,
} from '@elchinabilov/nestjs-signin';

@Controller('auth')
export class AuthController {
  constructor(private readonly signInService: SignInService) {}

  @Post('social-login')
  async socialLogin(@Body() dto: VerifyTokenDto): Promise<SignInUser> {
    const user = await this.signInService.verifyToken(dto.provider, dto.token);

    // user.provider     -> 'google' | 'apple'
    // user.providerId   -> unique ID from the provider
    // user.email        -> user's email (if available)
    // user.emailVerified -> whether the email is verified
    // user.firstName    -> first name (Google only)
    // user.lastName     -> last name (Google only)
    // user.fullName     -> full name (Google only)
    // user.avatar       -> profile picture URL (Google only)
    // user.raw          -> original payload from the provider

    return user;
  }
}

Async Configuration

Use forRootAsync() when your configuration depends on other services (e.g., ConfigService):

import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SignInModule } from '@elchinabilov/nestjs-signin';

@Module({
  imports: [
    ConfigModule.forRoot(),
    SignInModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (configService: ConfigService) => ({
        google: {
          clientIds: configService
            .get<string>('GOOGLE_CLIENT_IDS')!
            .split(','),
        },
        apple: {
          clientIds: [configService.get<string>('APPLE_CLIENT_ID')!],
        },
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Using a Factory Class

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import {
  SignInModuleOptionsFactory,
  SignInModuleConfig,
} from '@elchinabilov/nestjs-signin';

@Injectable()
export class SignInConfigService implements SignInModuleOptionsFactory {
  constructor(private readonly configService: ConfigService) {}

  createSignInOptions(): SignInModuleConfig {
    return {
      google: {
        clientIds: this.configService
          .get<string>('GOOGLE_CLIENT_IDS')!
          .split(','),
      },
      apple: {
        clientIds: [this.configService.get<string>('APPLE_CLIENT_ID')!],
      },
    };
  }
}
SignInModule.forRootAsync({
  imports: [ConfigModule],
  useClass: SignInConfigService,
});

Single Provider Setup

You can configure only the providers you need. Unconfigured providers will throw a ProviderNotConfiguredException if accessed:

// Google only
SignInModule.forRoot({
  google: {
    clientIds: ['YOUR_GOOGLE_CLIENT_ID'],
  },
});

// Apple only
SignInModule.forRoot({
  apple: {
    clientIds: ['YOUR_APPLE_SERVICE_ID'],
  },
});

API Reference

SignInService

| Method | Return Type | Description | | -------------------------------- | --------------------- | ------------------------------------------------ | | verifyToken(provider, token) | Promise<SignInUser> | Verifies a token and returns the normalized user | | getConfiguredProviders() | SignInProvider[] | Returns a list of configured providers | | isProviderConfigured(provider) | boolean | Checks if a specific provider is configured |

SignInUser Interface

| Field | Type | Description | | --------------- | ------------------------- | --------------------------------------- | | provider | SignInProvider | The provider used (google or apple) | | providerId | string | Unique user ID from the provider | | email | string | null | User's email address | | emailVerified | boolean | Whether the email is verified | | firstName | string | null | User's first name | | lastName | string | null | User's last name | | fullName | string | null | User's full name | | avatar | string | null | Profile picture URL | | raw | Record<string, unknown> | Original payload from the provider |

SignInProvider Enum

| Value | Description | | -------- | -------------- | | google | Google Sign-In | | apple | Apple Sign-In |

Exceptions

| Exception | HTTP Status | Description | | -------------------------------- | ----------- | ------------------------------------------ | | SignInException | 401 | Base exception for all sign-in errors | | InvalidTokenException | 401 | The provided token is invalid | | TokenExpiredException | 401 | The provided token has expired | | ProviderNotConfiguredException | 500 | The requested provider is not configured | | ProviderVerificationException | 401 | Token verification failed on provider side |

VerifyTokenDto

Pre-built DTO with class-validator decorators:

{
  "provider": "google",  // 'google' | 'apple'
  "token": "eyJhbGciOi..."
}

Provider Details

Google Sign-In

Google provider uses the official google-auth-library to verify ID tokens. It supports multiple client IDs (web, iOS, Android).

What you get:

  • providerId - Google user ID (sub claim)
  • email - User's email
  • emailVerified - Email verification status
  • firstName - Given name
  • lastName - Family name
  • fullName - Display name
  • avatar - Profile picture URL

Apple Sign-In

Apple provider verifies ID tokens by fetching Apple's public JWKS keys, with built-in caching (24h TTL). Apple provides limited user data.

What you get:

  • providerId - Apple user ID (sub claim)
  • email - User's email (may be a private relay email)
  • emailVerified - Email verification status
  • firstName - null (Apple does not include this in the token)
  • lastName - null (Apple does not include this in the token)
  • fullName - null (Apple does not include this in the token)
  • avatar - null (Apple does not provide this)

Note: Apple only sends user's name on the first authorization. You must capture it from the client-side authorization response and save it in your database.

Error Handling

import {
  SignInService,
  SignInProvider,
  InvalidTokenException,
  TokenExpiredException,
  ProviderNotConfiguredException,
} from '@elchinabilov/nestjs-signin';

@Controller('auth')
export class AuthController {
  constructor(private readonly signInService: SignInService) {}

  @Post('social-login')
  async socialLogin(@Body() dto: VerifyTokenDto) {
    try {
      const user = await this.signInService.verifyToken(
        dto.provider,
        dto.token,
      );
      return { success: true, user };
    } catch (error) {
      if (error instanceof InvalidTokenException) {
        // Token is invalid or tampered
      }
      if (error instanceof TokenExpiredException) {
        // Token has expired - client should refresh
      }
      if (error instanceof ProviderNotConfiguredException) {
        // Provider not set up in module config
      }
      throw error;
    }
  }
}

Environment Variables Example

# Google
GOOGLE_CLIENT_IDS=web-client-id.apps.googleusercontent.com,ios-client-id.apps.googleusercontent.com,android-client-id.apps.googleusercontent.com

# Apple
APPLE_CLIENT_ID=com.your.app.service

Requirements

  • Node.js >= 18.0.0
  • NestJS >= 9.0.0

License

ISC