{"_id":"@ace-common/auth","_rev":"3-27be3f9f3577a04bbba4114ddd17dc2d","name":"@ace-common/auth","dist-tags":{"latest":"3.0.2"},"versions":{"3.0.0":{"name":"@ace-common/auth","version":"3.0.0","keywords":["nestjs","auth","jwt","oauth","phone-otp","guard"],"license":"MIT","_id":"@ace-common/auth@3.0.0","maintainers":[{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"}],"dist":{"shasum":"51cd0ba3a5aab92c05607188d98dfe3a6be64300","tarball":"https://registry.npmjs.org/@ace-common/auth/-/auth-3.0.0.tgz","fileCount":71,"integrity":"sha512-BWtixlCe6pECSPVzjU2Nk+k3K2/P7Diw4xhDcN1D8kz/aA/qDGEN0L9UR50BYRjZgBd4xNVWVi/TGnvcQ2GSgQ==","signatures":[{"sig":"MEYCIQDLcvrBoh6RTDf+5O70VGeNiXeYQ6FvNIyOTFi0kdSM2wIhAMbjp3M04TpJTxzYucOewjRqjXVpEpTTjq1C2169YeAX","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":66045},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"ac4fdd90d14ab284281c1cabdd37c21e840dcb65","scripts":{"lint":"eslint 'src/**/*.ts'","build":"tsc","clean":"rm -rf dist","lint:fix":"eslint 'src/**/*.ts' --fix","prepublishOnly":"npm run clean && npm run lint && npm run build"},"_npmUser":{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"},"_npmVersion":"10.8.2","description":"Reusable, type-safe NestJS authentication library","directories":{},"_nodeVersion":"20.20.2","dependencies":{"jose":"^6.2.2","jsonwebtoken":"^9.0.3","google-auth-library":"^10.6.2"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.30.1+sha512.3590e550d5384caa39bd5c7c739f72270234b2f6059e13018f975c313b1eb9fefcc09714048765d4d9efe961382c312e624572c0420762bdc5d5940cdf9be73a","devDependencies":{"rxjs":"^7.8.0","eslint":"^9.17.0","@eslint/js":"^9.0.0","typescript":"^5.5.0","@types/node":"^25.5.0","@nestjs/core":"^11.0.0","@nestjs/common":"^11.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.0.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","reflect-metadata":">=0.1.13"},"_npmOperationalInternal":{"tmp":"tmp/auth_3.0.0_1775176828729_0.6169012328075099","host":"s3://npm-registry-packages-npm-production"}},"3.0.1":{"name":"@ace-common/auth","version":"3.0.1","keywords":["nestjs","auth","jwt","oauth","phone-otp","guard"],"license":"MIT","_id":"@ace-common/auth@3.0.1","maintainers":[{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"}],"dist":{"shasum":"33b8800d4b6a3ca7e0f644b15c729942cbed66ef","tarball":"https://registry.npmjs.org/@ace-common/auth/-/auth-3.0.1.tgz","fileCount":71,"integrity":"sha512-J6bSHeEhG5hWrqQnZ2PrZpc/GiwqIrE0Dlk88GJ+YGWaEGqojp5VL7XZes2f5gEI4bJT93sZ5eCXDwDyBh+iOQ==","signatures":[{"sig":"MEYCIQCLlMDdmbyHc7F2qSlz76d37AuxWZDEMmRMR5edaM1MZgIhAIeC0J8BXmxPa/3HKQa9/AVANpSctzSW13Zbg+YFgTuT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":66042},"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"7331b481fbf8b8b8c3b4df6d873378765848d1d2","scripts":{"lint":"eslint 'src/**/*.ts'","build":"tsc","clean":"rm -rf dist","lint:fix":"eslint 'src/**/*.ts' --fix","prepublishOnly":"npm run clean && npm run lint && npm run build"},"_npmUser":{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"},"_npmVersion":"10.9.7","description":"Reusable, type-safe NestJS authentication library","directories":{},"_nodeVersion":"22.22.2","dependencies":{"jose":"^6.2.2","jsonwebtoken":"^9.0.3","google-auth-library":"^10.6.2"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.30.1+sha512.3590e550d5384caa39bd5c7c739f72270234b2f6059e13018f975c313b1eb9fefcc09714048765d4d9efe961382c312e624572c0420762bdc5d5940cdf9be73a","devDependencies":{"rxjs":"^7.8.0","eslint":"^9.17.0","@eslint/js":"^9.0.0","typescript":"^5.5.0","@types/node":">=18","@nestjs/core":"^11.0.0","@nestjs/common":"^11.0.0","reflect-metadata":"^0.2.0","typescript-eslint":"^8.0.0","@types/jsonwebtoken":"^9.0.0"},"peerDependencies":{"rxjs":">=7.0.0","@nestjs/core":">=10.0.0","@nestjs/common":">=10.0.0","reflect-metadata":">=0.1.13"},"_npmOperationalInternal":{"tmp":"tmp/auth_3.0.1_1775306840114_0.8523803637851475","host":"s3://npm-registry-packages-npm-production"}},"3.0.2":{"name":"@ace-common/auth","version":"3.0.2","description":"Reusable, type-safe NestJS authentication library","license":"MIT","keywords":["nestjs","auth","jwt","oauth","phone-otp","guard"],"main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"scripts":{"build":"tsc","lint":"eslint 'src/**/*.ts'","lint:fix":"eslint 'src/**/*.ts' --fix","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run lint && npm run build"},"peerDependencies":{"@nestjs/common":">=10.0.0","@nestjs/core":">=10.0.0","reflect-metadata":">=0.1.13","rxjs":">=7.0.0"},"devDependencies":{"@eslint/js":"^9.0.0","@nestjs/common":"^11.0.0","@nestjs/core":"^11.0.0","@types/jsonwebtoken":"^9.0.0","@types/node":">=18","eslint":"^9.17.0","reflect-metadata":"^0.2.0","rxjs":"^7.8.0","typescript":"^5.5.0","typescript-eslint":"^8.0.0"},"dependencies":{"google-auth-library":"^10.6.2","jose":"^6.2.2","jsonwebtoken":"^9.0.3"},"packageManager":"pnpm@10.30.1+sha512.3590e550d5384caa39bd5c7c739f72270234b2f6059e13018f975c313b1eb9fefcc09714048765d4d9efe961382c312e624572c0420762bdc5d5940cdf9be73a","_id":"@ace-common/auth@3.0.2","gitHead":"724c295f983b8c963c1e893a6e717c0659eda48b","_nodeVersion":"22.22.2","_npmVersion":"10.9.7","dist":{"integrity":"sha512-GyYDHLNlro8tj4L/njPwXrq94bnjHNMB/dK0vHkzwpezmxtlZH+Q499aSXlHkRZgsN8+JOgIWjx6kPROqKNFpw==","shasum":"dac2c8fa6e64ecc6a3e74afe184b8279672c939d","tarball":"https://registry.npmjs.org/@ace-common/auth/-/auth-3.0.2.tgz","fileCount":71,"unpackedSize":67498,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBLfV1LvjBmtLiuUZkOG9fRgzV1QZ5dewY7eW6Jceo0xAiAx+VHo4dqLKLhqB4H5Fsc33K5dUK4xv9R6fgiE6IS1BA=="}]},"_npmUser":{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"},"directories":{},"maintainers":[{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/auth_3.0.2_1776032487693_0.20740289762034037"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-03T00:40:28.674Z","modified":"2026-04-12T22:21:27.991Z","3.0.0":"2026-04-03T00:40:28.865Z","3.0.1":"2026-04-04T12:47:20.269Z","3.0.2":"2026-04-12T22:21:27.823Z"},"license":"MIT","keywords":["nestjs","auth","jwt","oauth","phone-otp","guard"],"description":"Reusable, type-safe NestJS authentication library","maintainers":[{"name":"mohamedmostafa0","email":"mohamed.it.999@hotmail.com"}],"readme":"# @ace-common/auth\n\nReusable, type-safe NestJS authentication library with JWT, OAuth (Google, Facebook, Apple), and phone OTP support.\n\n## Installation\n\n```bash\npnpm add @ace-common/auth\n```\n\nPeer dependencies: `@nestjs/common`, `@nestjs/core`, `reflect-metadata`, `rxjs`.\n\n## Quick Start\n\n### Synchronous config\n\n```typescript\nimport { configureAuth } from '@ace-common/auth';\n\n@Module({\n  imports: [\n    configureAuth<User>({\n      jwtSecret: 'your-secret',\n      jwtExpiresIn: '7d', // optional, defaults to \"1h\"\n      userAdapter: MyUserAdapter,\n      oauth: {\n        google: { clientId: '...' },\n        facebook: { appId: '...', appSecret: '...' },\n        apple: { clientId: '...' },\n      },\n      phone: {\n        verifyCode: (phone, code) => twilioVerify(phone, code),\n        normalizePhone: (p) => p.replace(/\\s/g, ''),\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### Async config (e.g. with `ConfigService`)\n\n```typescript\nimport { configureAuthAsync } from '@ace-common/auth';\nimport { ConfigService } from '@nestjs/config';\n\n@Module({\n  imports: [\n    configureAuthAsync<User>({\n      userAdapter: MyUserAdapter,\n      imports: [ConfigModule],\n      inject: [ConfigService],\n      useFactory: (config: ConfigService) => ({\n        jwtSecret: config.getOrThrow('JWT_SECRET'),\n        jwtExpiresIn: config.get('JWT_EXPIRES_IN', '1h'),\n        oauth: {\n          google: { clientId: config.getOrThrow('GOOGLE_CLIENT_ID') },\n        },\n      }),\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n## UserAdapter\n\nImplement the `UserAdapter` interface to connect the library to your data layer:\n\n```typescript\n@Injectable()\nexport class MyUserAdapter implements UserAdapter<User> {\n  findById(id: string): Observable<User | null> { /* ... */ }\n  findOneBy(criteria: Partial<User>): Observable<User | null> { /* ... */ }\n  findOrCreate?(criteria: Partial<User>, data: Partial<User>): Observable<User> { /* ... */ }\n  create?(data: Partial<User>): Observable<User> { /* ... */ }\n}\n```\n\nRequired: `findById`, `findOneBy`.\nFor OAuth/phone flows: implement `findOrCreate` or `create`.\n\n## Controller Usage\n\n```typescript\n@Controller('auth')\n@UseFilters(AuthExceptionFilter)\nexport class AuthController {\n  constructor(private readonly authService: AuthService<User>) {}\n\n  @Post('google')\n  login(@Body() dto: OAuthLoginDto) {\n    return firstValueFrom(this.authService.authenticateOAuth('google', dto.token));\n  }\n\n  @Post('phone')\n  loginPhone(@Body() dto: PhoneLoginDto) {\n    return firstValueFrom(this.authService.authenticatePhone(dto.phone, dto.code));\n  }\n\n  @Get('profile')\n  @UseGuards(AuthGuard)\n  getProfile(@CurrentUser() jwt: JwtPayload) {\n    return firstValueFrom(this.authService.findUserById(jwt.sub));\n  }\n}\n```\n\n## Error Handling\n\nApply `AuthExceptionFilter` at the **controller** level (not globally) so it only handles auth routes:\n\n```typescript\n@Controller('auth')\n@UseFilters(AuthExceptionFilter)\nexport class AuthController { /* ... */ }\n```\n\nAll auth errors follow a consistent shape:\n\n```json\n{\n  \"statusCode\": 401,\n  \"errorCode\": \"AUTH_INVALID_TOKEN\",\n  \"message\": \"Token has expired\",\n  \"timestamp\": \"2026-04-03T12:00:00.000Z\"\n}\n```\n\n## Exports\n\n| Export | Description |\n|---|---|\n| `configureAuth` / `configureAuthAsync` | Module configuration helpers |\n| `AuthModule` | NestJS dynamic module (`forRoot` / `forRootAsync`) |\n| `AuthService` | JWT signing/verification, OAuth, phone auth |\n| `AuthGuard` | Route guard — validates Bearer token |\n| `CurrentUser` | Parameter decorator — extracts JWT payload |\n| `AuthException` | Base exception class for all auth errors |\n| `AuthExceptionFilter` | Exception filter scoped to `AuthException` |\n| `AuthErrorCode` | Enum of all error codes |\n| `UserAdapter` | Interface for your data layer |\n\n## License\n\nMIT\n","readmeFilename":"README.md"}