{"_id":"@elchinabilov/nestjs-signin","_rev":"2-ed6afd37abca932d7a839d63a276945b","name":"@elchinabilov/nestjs-signin","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@elchinabilov/nestjs-signin","version":"1.0.0","keywords":["nestjs","signin","sign-in","social-login","google-signin","apple-signin","google-auth","apple-auth","oauth","authentication","token-verification","id-token","social-auth","nestjs-module","nestjs-auth"],"author":{"name":"Elchin Abilov","email":"abilovelchin@gmail.com"},"license":"ISC","_id":"@elchinabilov/nestjs-signin@1.0.0","maintainers":[{"name":"abilov","email":"abilovelchin@gmail.com"}],"homepage":"https://github.com/elchinabilov/nestjs-signin#readme","bugs":{"url":"https://github.com/elchinabilov/nestjs-signin/issues"},"dist":{"shasum":"e771dbe112b257fdd1ec8565ed1bac05ad1909d1","tarball":"https://registry.npmjs.org/@elchinabilov/nestjs-signin/-/nestjs-signin-1.0.0.tgz","fileCount":45,"integrity":"sha512-QbYekmzivwFo+fnRIbbXjwNy04usBZOc7HhgZUDm+1kPPc2V3nXqXcTW49plIJe9X0NqpzC8fzRj/PsXEokzWQ==","signatures":[{"sig":"MEUCIHwt6HuxzXdyWgVxyKpB8xxKBwVKRrF/F4/owGSS+cZwAiEAxTH6slRQ6aHrTPR7+MrIR5yHJDuk0hmHce7bD9zBEJM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":198063},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"scripts":{"lint":"eslint \"src/**/*.ts\" --fix","build":"tsc","format":"prettier --write \"src/**/*.ts\"","prepublish":"npm run build","prepublishOnly":"npm run build"},"_npmUser":{"name":"abilov","email":"abilovelchin@gmail.com"},"repository":{"url":"git+https://github.com/elchinabilov/nestjs-signin.git","type":"git"},"_npmVersion":"11.7.0","description":"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.","directories":{},"_nodeVersion":"22.19.0","dependencies":{"jsonwebtoken":"^9.0.0","google-auth-library":"^9.0.0"},"_hasShrinkwrap":false,"devDependencies":{"rxjs":"latest","eslint":"latest","prettier":"latest","typescript":"latest","@types/node":"latest","@nestjs/core":"latest","@nestjs/common":"latest","class-validator":"latest","reflect-metadata":"latest","class-transformer":"latest","@types/jsonwebtoken":"latest","eslint-config-prettier":"latest","eslint-plugin-prettier":"latest","@nestjs/platform-express":"latest","@typescript-eslint/parser":"latest","@typescript-eslint/eslint-plugin":"latest"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=9.0.0","@nestjs/common":">=9.0.0","class-validator":">=0.14.0","reflect-metadata":">=0.1.13","class-transformer":">=0.5.0"},"peerDependenciesMeta":{"class-validator":{"optional":true},"class-transformer":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-signin_1.0.0_1771584495658_0.7315089101338375","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@elchinabilov/nestjs-signin","version":"1.0.1","description":"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.","author":{"name":"Elchin Abilov","email":"abilovelchin@gmail.com"},"license":"ISC","keywords":["nestjs","signin","sign-in","social-login","google-signin","apple-signin","google-auth","apple-auth","oauth","authentication","token-verification","id-token","social-auth","nestjs-module","nestjs-auth"],"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","format":"prettier --write \"src/**/*.ts\"","lint":"eslint \"src/**/*.ts\" --fix","prepublishOnly":"npm run build","prepublish":"npm run build"},"dependencies":{"@nestjs/swagger":"^11.2.6","google-auth-library":"^9.0.0","jsonwebtoken":"^9.0.0"},"peerDependencies":{"@nestjs/common":">=9.0.0","@nestjs/core":">=9.0.0","class-transformer":">=0.5.0","class-validator":">=0.14.0","reflect-metadata":">=0.1.13","rxjs":">=7.0.0"},"peerDependenciesMeta":{"class-validator":{"optional":true},"class-transformer":{"optional":true}},"devDependencies":{"@nestjs/common":"latest","@nestjs/core":"latest","@nestjs/platform-express":"latest","@types/jsonwebtoken":"latest","@types/node":"latest","@typescript-eslint/eslint-plugin":"latest","@typescript-eslint/parser":"latest","class-transformer":"latest","class-validator":"latest","eslint":"latest","eslint-config-prettier":"latest","eslint-plugin-prettier":"latest","prettier":"latest","reflect-metadata":"latest","rxjs":"latest","typescript":"latest"},"engines":{"node":">=18.0.0"},"repository":{"type":"git","url":"git+https://github.com/elchinabilov/nestjs-signin.git"},"bugs":{"url":"https://github.com/elchinabilov/nestjs-signin/issues"},"homepage":"https://github.com/elchinabilov/nestjs-signin#readme","_id":"@elchinabilov/nestjs-signin@1.0.1","_nodeVersion":"22.19.0","_npmVersion":"11.7.0","dist":{"integrity":"sha512-yshE4MuSNh2UuhJAF8rJmK/BEwdIn54pizQFn+MxlnM98Rpq15WaEJaSkGQJdodT5ClV+o5lZH6aNS9AqMNX4g==","shasum":"fb4ae98ae36f9b1260de0865baf4783797da0eb0","tarball":"https://registry.npmjs.org/@elchinabilov/nestjs-signin/-/nestjs-signin-1.0.1.tgz","fileCount":45,"unpackedSize":207179,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHfzjQrjDZEJPwWVJvJi0WXVsAWcubZl3YHF1AUQ6qmjAiEA1vcTC2/W0t7qvfEfaLcAsLbladW6KlL449g3dqb3ZF0="}]},"_npmUser":{"name":"abilov","email":"abilovelchin@gmail.com"},"directories":{},"maintainers":[{"name":"abilov","email":"abilovelchin@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-signin_1.0.1_1771585152912_0.8250598582619042"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-20T10:48:15.557Z","modified":"2026-02-20T10:59:13.273Z","1.0.0":"2026-02-20T10:48:15.831Z","1.0.1":"2026-02-20T10:59:13.131Z"},"bugs":{"url":"https://github.com/elchinabilov/nestjs-signin/issues"},"author":{"name":"Elchin Abilov","email":"abilovelchin@gmail.com"},"license":"ISC","homepage":"https://github.com/elchinabilov/nestjs-signin#readme","keywords":["nestjs","signin","sign-in","social-login","google-signin","apple-signin","google-auth","apple-auth","oauth","authentication","token-verification","id-token","social-auth","nestjs-module","nestjs-auth"],"repository":{"type":"git","url":"git+https://github.com/elchinabilov/nestjs-signin.git"},"description":"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.","maintainers":[{"name":"abilov","email":"abilovelchin@gmail.com"}],"readme":"# @elchinabilov/nestjs-signin\n\nA 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.\n\n## Features\n\n- **Google Sign-In** - Verify Google ID tokens using the official `google-auth-library`\n- **Apple Sign-In** - Verify Apple ID tokens with JWKS public key validation\n- **Unified API** - Single `verifyToken()` method for all providers\n- **Normalized User Profile** - Consistent `SignInUser` interface across all providers\n- **Dynamic Module** - Supports both `forRoot()` and `forRootAsync()` patterns\n- **Global Module** - Register once, use anywhere in your application\n- **Type-Safe** - Full TypeScript support with comprehensive type definitions\n- **Custom Exceptions** - Descriptive error types for different failure scenarios\n- **Built-in DTO** - Ready-to-use `VerifyTokenDto` with `class-validator` decorators\n- **Extensible** - Easy to add new providers in the future\n\n## Installation\n\n```bash\nnpm install @elchinabilov/nestjs-signin\n```\n\n### Peer Dependencies\n\nMake sure you have the following packages installed in your NestJS project:\n\n```bash\nnpm install @nestjs/common @nestjs/core reflect-metadata rxjs\n```\n\nOptional (for DTO validation):\n\n```bash\nnpm install class-validator class-transformer\n```\n\n## Quick Start\n\n### 1. Register the Module\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { SignInModule } from '@elchinabilov/nestjs-signin';\n\n@Module({\n  imports: [\n    SignInModule.forRoot({\n      google: {\n        clientIds: [\n          'YOUR_GOOGLE_WEB_CLIENT_ID',\n          'YOUR_GOOGLE_IOS_CLIENT_ID',\n          'YOUR_GOOGLE_ANDROID_CLIENT_ID',\n        ],\n      },\n      apple: {\n        clientIds: ['YOUR_APPLE_SERVICE_ID'],\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### 2. Use the Service\n\n```typescript\nimport { Controller, Post, Body } from '@nestjs/common';\nimport {\n  SignInService,\n  SignInProvider,\n  SignInUser,\n  VerifyTokenDto,\n} from '@elchinabilov/nestjs-signin';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private readonly signInService: SignInService) {}\n\n  @Post('social-login')\n  async socialLogin(@Body() dto: VerifyTokenDto): Promise<SignInUser> {\n    const user = await this.signInService.verifyToken(dto.provider, dto.token);\n\n    // user.provider     -> 'google' | 'apple'\n    // user.providerId   -> unique ID from the provider\n    // user.email        -> user's email (if available)\n    // user.emailVerified -> whether the email is verified\n    // user.firstName    -> first name (Google only)\n    // user.lastName     -> last name (Google only)\n    // user.fullName     -> full name (Google only)\n    // user.avatar       -> profile picture URL (Google only)\n    // user.raw          -> original payload from the provider\n\n    return user;\n  }\n}\n```\n\n## Async Configuration\n\nUse `forRootAsync()` when your configuration depends on other services (e.g., `ConfigService`):\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { ConfigModule, ConfigService } from '@nestjs/config';\nimport { SignInModule } from '@elchinabilov/nestjs-signin';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    SignInModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (configService: ConfigService) => ({\n        google: {\n          clientIds: configService\n            .get<string>('GOOGLE_CLIENT_IDS')!\n            .split(','),\n        },\n        apple: {\n          clientIds: [configService.get<string>('APPLE_CLIENT_ID')!],\n        },\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Using a Factory Class\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { ConfigService } from '@nestjs/config';\nimport {\n  SignInModuleOptionsFactory,\n  SignInModuleConfig,\n} from '@elchinabilov/nestjs-signin';\n\n@Injectable()\nexport class SignInConfigService implements SignInModuleOptionsFactory {\n  constructor(private readonly configService: ConfigService) {}\n\n  createSignInOptions(): SignInModuleConfig {\n    return {\n      google: {\n        clientIds: this.configService\n          .get<string>('GOOGLE_CLIENT_IDS')!\n          .split(','),\n      },\n      apple: {\n        clientIds: [this.configService.get<string>('APPLE_CLIENT_ID')!],\n      },\n    };\n  }\n}\n```\n\n```typescript\nSignInModule.forRootAsync({\n  imports: [ConfigModule],\n  useClass: SignInConfigService,\n});\n```\n\n## Single Provider Setup\n\nYou can configure only the providers you need. Unconfigured providers will throw a `ProviderNotConfiguredException` if accessed:\n\n```typescript\n// Google only\nSignInModule.forRoot({\n  google: {\n    clientIds: ['YOUR_GOOGLE_CLIENT_ID'],\n  },\n});\n\n// Apple only\nSignInModule.forRoot({\n  apple: {\n    clientIds: ['YOUR_APPLE_SERVICE_ID'],\n  },\n});\n```\n\n## API Reference\n\n### SignInService\n\n\n| Method                           | Return Type           | Description                                      |\n| -------------------------------- | --------------------- | ------------------------------------------------ |\n| `verifyToken(provider, token)`   | `Promise<SignInUser>` | Verifies a token and returns the normalized user |\n| `getConfiguredProviders()`       | `SignInProvider[]`    | Returns a list of configured providers           |\n| `isProviderConfigured(provider)` | `boolean`             | Checks if a specific provider is configured      |\n\n\n### SignInUser Interface\n\n\n| Field           | Type                      | Description                             |\n| --------------- | ------------------------- | --------------------------------------- |\n| `provider`      | `SignInProvider`          | The provider used (`google` or `apple`) |\n| `providerId`    | `string`                  | Unique user ID from the provider        |\n| `email`         | `string | null`           | User's email address                    |\n| `emailVerified` | `boolean`                 | Whether the email is verified           |\n| `firstName`     | `string | null`           | User's first name                       |\n| `lastName`      | `string | null`           | User's last name                        |\n| `fullName`      | `string | null`           | User's full name                        |\n| `avatar`        | `string | null`           | Profile picture URL                     |\n| `raw`           | `Record<string, unknown>` | Original payload from the provider      |\n\n\n### SignInProvider Enum\n\n\n| Value    | Description    |\n| -------- | -------------- |\n| `google` | Google Sign-In |\n| `apple`  | Apple Sign-In  |\n\n\n### Exceptions\n\n\n| Exception                        | HTTP Status | Description                                |\n| -------------------------------- | ----------- | ------------------------------------------ |\n| `SignInException`                | 401         | Base exception for all sign-in errors      |\n| `InvalidTokenException`          | 401         | The provided token is invalid              |\n| `TokenExpiredException`          | 401         | The provided token has expired             |\n| `ProviderNotConfiguredException` | 500         | The requested provider is not configured   |\n| `ProviderVerificationException`  | 401         | Token verification failed on provider side |\n\n\n### VerifyTokenDto\n\nPre-built DTO with `class-validator` decorators:\n\n```typescript\n{\n  \"provider\": \"google\",  // 'google' | 'apple'\n  \"token\": \"eyJhbGciOi...\"\n}\n```\n\n## Provider Details\n\n### Google Sign-In\n\nGoogle provider uses the official `google-auth-library` to verify ID tokens. It supports multiple client IDs (web, iOS, Android).\n\n**What you get:**\n\n- `providerId` - Google user ID (`sub` claim)\n- `email` - User's email\n- `emailVerified` - Email verification status\n- `firstName` - Given name\n- `lastName` - Family name\n- `fullName` - Display name\n- `avatar` - Profile picture URL\n\n### Apple Sign-In\n\nApple provider verifies ID tokens by fetching Apple's public JWKS keys, with built-in caching (24h TTL). Apple provides limited user data.\n\n**What you get:**\n\n- `providerId` - Apple user ID (`sub` claim)\n- `email` - User's email (may be a private relay email)\n- `emailVerified` - Email verification status\n- `firstName` - `null` (Apple does not include this in the token)\n- `lastName` - `null` (Apple does not include this in the token)\n- `fullName` - `null` (Apple does not include this in the token)\n- `avatar` - `null` (Apple does not provide this)\n\n> **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.\n\n## Error Handling\n\n```typescript\nimport {\n  SignInService,\n  SignInProvider,\n  InvalidTokenException,\n  TokenExpiredException,\n  ProviderNotConfiguredException,\n} from '@elchinabilov/nestjs-signin';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private readonly signInService: SignInService) {}\n\n  @Post('social-login')\n  async socialLogin(@Body() dto: VerifyTokenDto) {\n    try {\n      const user = await this.signInService.verifyToken(\n        dto.provider,\n        dto.token,\n      );\n      return { success: true, user };\n    } catch (error) {\n      if (error instanceof InvalidTokenException) {\n        // Token is invalid or tampered\n      }\n      if (error instanceof TokenExpiredException) {\n        // Token has expired - client should refresh\n      }\n      if (error instanceof ProviderNotConfiguredException) {\n        // Provider not set up in module config\n      }\n      throw error;\n    }\n  }\n}\n```\n\n## Environment Variables Example\n\n```env\n# Google\nGOOGLE_CLIENT_IDS=web-client-id.apps.googleusercontent.com,ios-client-id.apps.googleusercontent.com,android-client-id.apps.googleusercontent.com\n\n# Apple\nAPPLE_CLIENT_ID=com.your.app.service\n```\n\n## Requirements\n\n- Node.js >= 18.0.0\n- NestJS >= 9.0.0\n\n## License\n\nISC","readmeFilename":"README.md"}