{"id":30741845,"url":"https://github.com/microhd/authflow-phantom","last_synced_at":"2025-09-04T01:02:37.704Z","repository":{"id":294566072,"uuid":"987363665","full_name":"MicroHD/authflow-phantom","owner":"MicroHD","description":"🔐 Secure, passwordless authentication for NestJS - Phantom Links, WebAuthn, and Magic Links","archived":false,"fork":false,"pushed_at":"2025-05-23T04:35:03.000Z","size":198,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-02T17:59:00.379Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MicroHD.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-21T01:13:28.000Z","updated_at":"2025-05-23T04:35:06.000Z","dependencies_parsed_at":"2025-05-21T03:38:24.159Z","dependency_job_id":null,"html_url":"https://github.com/MicroHD/authflow-phantom","commit_stats":null,"previous_names":["microhd/authflow-phantom"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MicroHD/authflow-phantom","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroHD%2Fauthflow-phantom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroHD%2Fauthflow-phantom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroHD%2Fauthflow-phantom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroHD%2Fauthflow-phantom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MicroHD","download_url":"https://codeload.github.com/MicroHD/authflow-phantom/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MicroHD%2Fauthflow-phantom/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273534568,"owners_count":25122679,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-03T02:00:09.631Z","response_time":76,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-04T01:02:36.764Z","updated_at":"2025-09-04T01:02:37.670Z","avatar_url":"https://github.com/MicroHD.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @auth-flow/phantom\n\n[![npm version](https://badge.fury.io/js/%40authflow%2Fphantom.svg)](https://badge.fury.io/js/%40authflow%2Fphantom)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)\n[![NestJS](https://img.shields.io/badge/NestJS-Compatible-red.svg)](https://nestjs.com/)\n[![Bun](https://img.shields.io/badge/Bun-Compatible-000000.svg)](https://bun.sh/)\n\nA secure, passwordless authentication library for NestJS applications. Built with TypeScript and designed for modern web applications.\n\n## 🌟 Features\n\n- 🔐 **Phantom Links**: Secure, one-time, short-lived links tied to user/device context\n- 💾 **Device Memory Tokens**: Local device tokens for seamless re-login\n- 📧 **Email Magic Links**: Passwordless login via email\n- 🎯 **WebAuthn Support**: FIDO2/WebAuthn authentication\n- 🛡️ **Security Features**:\n  - Rate limiting\n  - Context verification\n  - IP-based blocking\n  - Challenge expiration\n  - Secure token generation\n  - Redis-backed session management\n  - JWT token support\n\n## 📦 Installation\n\n```bash\n# Using bun (recommended)\nbun add @auth-flow/phantom\n\n# Using npm\nnpm install @auth-flow/phantom\n\n# Using yarn\nyarn add @auth-flow/phantom\n```\n\n## 🔑 Getting Started\n\n1. **Generate API Key**\n\nYou can generate your API key in two ways:\n\n```bash\n# Method 1: Using the CLI tool\nbunx @auth-flow/phantom\n# or\nnpx @auth-flow/phantom\n\n# Method 2: Programmatically\nimport { ApiKeyService } from '@auth-flow/phantom';\n\nconst apiKeyService = new ApiKeyService();\nconst { apiKey, projectId } = apiKeyService.generateApiKey();\n```\n\nThis will generate your API key and Project ID. Add them to your `.env` file:\n\n```env\nAUTHFLOW_API_KEY=your_api_key_here\nAUTHFLOW_PROJECT_ID=your_project_id_here\n```\n\n2. **Install Dependencies**\n\n```bash\nbun add @auth-flow/phantom @nestjs/common @nestjs/core\n```\n\n3. **Environment Setup**\n\nAdd these to your `.env` file:\n\n```env\n# Database Configuration\nDATABASE_URL=postgresql://user:password@localhost:5432/dbname\n\n# Redis Configuration\nREDIS_HOST=localhost\nREDIS_PORT=6379\nREDIS_PASSWORD=your-redis-password\n\n# Email Configuration\nSMTP_HOST=smtp.example.com\nSMTP_PORT=587\nSMTP_USER=your-smtp-user\nSMTP_PASS=your-smtp-password\nSMTP_FROM=noreply@example.com\n\n# JWT Configuration\nJWT_SECRET=your-secret-key-here\n\n# WebAuthn Configuration (Optional)\nWEBAUTHN_RP_NAME=Your App Name\nWEBAUTHN_RP_ID=yourdomain.com\nWEBAUTHN_ORIGIN=https://yourdomain.com\n```\n\n4. **Module Integration**\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { AuthFlowModule } from '@auth-flow/phantom';\n\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      database: {\n        url: process.env.DATABASE_URL,\n      },\n      redis: {\n        host: process.env.REDIS_HOST,\n        port: parseInt(process.env.REDIS_PORT),\n        password: process.env.REDIS_PASSWORD,\n      },\n      email: {\n        host: process.env.SMTP_HOST,\n        port: parseInt(process.env.SMTP_PORT),\n        secure: true,\n        auth: {\n          user: process.env.SMTP_USER,\n          pass: process.env.SMTP_PASS,\n        },\n        from: process.env.SMTP_FROM,\n      },\n      jwt: {\n        secret: process.env.JWT_SECRET,\n        expiresIn: '7d',\n      },\n      webauthn: {\n        rpName: process.env.WEBAUTHN_RP_NAME,\n        rpID: process.env.WEBAUTHN_RP_ID,\n        origin: process.env.WEBAUTHN_ORIGIN,\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n5. **Controller Implementation**\n\n```typescript\nimport { Controller, Post, Body, Req, UseGuards } from '@nestjs/common';\nimport { AuthFlowService, AuthGuard } from '@auth-flow/phantom';\nimport { Request } from 'express';\n\n@Controller('auth')\nexport class AuthController {\n  constructor(private readonly authFlow: AuthFlowService) {}\n\n  @Post('login')\n  async login(@Body('email') email: string) {\n    await this.authFlow.sendMagicLink(email);\n    return { message: 'Login link sent' };\n  }\n\n  @Post('verify')\n  async verify(@Body('token') token: string) {\n    const result = await this.authFlow.validateLogin(token);\n    return result;\n  }\n\n  @UseGuards(AuthGuard)\n  @Get('profile')\n  async getProfile(@Req() req: Request) {\n    return req.user;\n  }\n}\n```\n\n## 🔧 Configuration Options\n\n### AuthFlowModule Configuration\n\n```typescript\ninterface AuthFlowConfig {\n  database: {\n    url: string;\n  };\n  redis: {\n    host: string;\n    port: number;\n    password?: string;\n  };\n  email: {\n    host: string;\n    port: number;\n    secure: boolean;\n    auth: {\n      user: string;\n      pass: string;\n    };\n    from: string;\n  };\n  jwt: {\n    secret: string;\n    expiresIn: string;\n  };\n  webauthn?: {\n    rpName: string;\n    rpID: string;\n    origin: string;\n  };\n}\n```\n\n### Using Custom Redis Configuration\n\nYou can use your own Redis configuration in three ways:\n1. **Using the built-in SharedModule (default)**:\n```typescript\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n2. **Using your own Redis module**:\n```typescript\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }, {\n      useCustomRedis: true,\n      customRedisModule: YourRedisModule, // Your custom Redis module\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n3. **Providing RedisService globally**:\n```typescript\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }, { useCustomRedis: true }), // No custom module provided, app must provide RedisService\n  ],\n})\nexport class AppModule {}\n```\n\nNote: When using a custom Redis module or providing RedisService globally, make sure it implements the same interface as the built-in RedisService. The RedisService should provide these methods:\n- `get\u003cT\u003e(key: string): Promise\u003cT | null\u003e`\n- `set(key: string, value: any, ttl?: number): Promise\u003cvoid\u003e`\n- `del(key: string): Promise\u003cvoid\u003e`\n- `setWithExpiry(key: string, value: any, ttl: number): Promise\u003cvoid\u003e`\n\n### Using Custom Redis and Prisma Configuration\n\nYou can use your own Redis and Prisma configuration in several ways:\n\n1. **Using the built-in SharedModule (default)**:\n```typescript\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n2. **Using custom Redis and Prisma modules**:\n```typescript\n@Module({\n  imports: [\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }, {\n      useCustomRedis: true,\n      customRedisModule: YourRedisModule,\n      useCustomPrisma: true,\n      customPrismaModule: YourPrismaModule,\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n3. **Providing PrismaService globally**:\n```typescript\n// In your app's PrismaModule:\n@Module({\n  providers: [YourPrismaService],\n  exports: [YourPrismaService],\n})\nexport class PrismaModule {}\n\n// In your AppModule:\n@Module({\n  imports: [\n    PrismaModule, // Import your PrismaModule first\n    AuthFlowModule.forRoot({\n      // ... other config\n      redis: {\n        host: 'localhost',\n        port: 6379,\n        password: 'your-password'\n      },\n    }, {\n      useCustomPrisma: true, // No custom module provided, app must provide PrismaService\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\nNote: When using custom modules or providing services globally, make sure they implement the correct interfaces:\n\n**RedisService Interface:**\n```typescript\ninterface RedisService {\n  get\u003cT\u003e(key: string): Promise\u003cT | null\u003e;\n  set(key: string, value: any, ttl?: number): Promise\u003cvoid\u003e;\n  del(key: string): Promise\u003cvoid\u003e;\n  setWithExpiry(key: string, value: any, ttl: number): Promise\u003cvoid\u003e;\n}\n```\n\n**PrismaService Interface:**\n```typescript\ninterface PrismaService {\n  // Your Prisma client methods\n  user: {\n    findUnique: (args: any) =\u003e Promise\u003cany\u003e;\n    create: (args: any) =\u003e Promise\u003cany\u003e;\n    update: (args: any) =\u003e Promise\u003cany\u003e;\n    delete: (args: any) =\u003e Promise\u003cany\u003e;\n  };\n  // ... other Prisma models\n}\n```\n\n**Important**: When providing your own PrismaService:\n1. Make sure your PrismaService class implements all required methods\n2. Export your PrismaService from your module\n3. Import your PrismaModule before AuthFlowModule in your app\n4. If using a custom module, pass it through the `customPrismaModule` option\n\n## 🔐 Security Best Practices\n\n1. **Environment Variables**\n   - Use strong, unique secrets\n   - Never commit `.env` files\n   - Use different secrets for development and production\n\n2. **Rate Limiting**\n   - Configure appropriate limits based on your use case\n   - Monitor and adjust limits based on traffic patterns\n\n3. **Context Verification**\n   - Always verify request context\n   - Implement IP-based blocking for suspicious activity\n\n4. **Token Management**\n   - Use short expiry times for phantom links\n   - Implement proper token rotation\n   - Monitor token usage patterns\n\n5. **HTTPS**\n   - Always use HTTPS in production\n   - Configure proper SSL/TLS settings\n\n## 🧪 Testing\n\n```bash\n# Run tests\nbun test\n\n# Run tests with coverage\nbun test:cov\n\n# Run tests in watch mode\nbun test:watch\n```\n\n## 📚 API Documentation\n\n### AuthFlowService\n\n```typescript\nclass AuthFlowService {\n  sendMagicLink(email: string): Promise\u003cvoid\u003e;\n  validateLogin(token: string): Promise\u003cAuthResult\u003e;\n  refreshToken(token: string): Promise\u003cAuthResult\u003e;\n  logout(token: string): Promise\u003cvoid\u003e;\n}\n```\n\n### Guards\n\n```typescript\n@UseGuards(AuthGuard)\n```\n\n### Decorators\n\n```typescript\n@AuthUser()\n@RequireAuth()\n```\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\nPlease read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.\n\n## 📝 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- [NestJS](https://nestjs.com/)\n- [WebAuthn](https://webauthn.io/)\n- [Redis](https://redis.io/)\n- [TypeScript](https://www.typescriptlang.org/)\n\n## 📞 Support\n\n- [GitHub Issues](https://github.com/yourusername/authflow-phantom/issues)\n- [Documentation](https://docs.authflow.io/phantom)\n- [Discord Community](https://discord.gg/authflow)\n\n## 🔄 Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for a list of changes. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrohd%2Fauthflow-phantom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicrohd%2Fauthflow-phantom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrohd%2Fauthflow-phantom/lists"}