{"_id":"@autolabz/service-auth-nextjs","_rev":"4-1ae3934b8bb697d2a2685de761a06427","name":"@autolabz/service-auth-nextjs","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@autolabz/service-auth-nextjs","version":"1.0.0","_id":"@autolabz/service-auth-nextjs@1.0.0","maintainers":[{"name":"autolabz","email":"mzhh@mzhh.xyz"}],"dist":{"shasum":"82a38a1f6d72afaa2df54efb8c7f1437ab1b77f5","tarball":"https://registry.npmjs.org/@autolabz/service-auth-nextjs/-/service-auth-nextjs-1.0.0.tgz","fileCount":8,"integrity":"sha512-QeGa06sUkxW1/zGAfSesgJkgMfxnLDBimF+pGR0WMAsUxG7QwjQpEeWJHNLdtV/OBRRV5r6ZfZqNDX8OEyFa0g==","signatures":[{"sig":"MEUCIQCUdfPc9Zu+nx249S3D0rnRNFXWbja05MwNE5kS++84hQIgX0Uaj9YjYY8uWslazWXrHSfqYVspdBACgFK4x7lzTdI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35699},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"7aaed46abb7b0c16716e887d0501aadcd4b00fa6","scripts":{"build":"npm run clean && tsup src/index.ts --format esm,cjs --dts --sourcemap --clean --target node18","clean":"rimraf dist","prepare":"npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"autolabz","email":"mzhh@mzhh.xyz"},"_npmVersion":"10.8.2","description":"Next.js App Router authentication utilities for AutoLab services","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"@autolabz/service-auth-core":"file:../service-auth-core"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","rimraf":"^5.0.5","typescript":"^5.6.3"},"_npmOperationalInternal":{"tmp":"tmp/service-auth-nextjs_1.0.0_1763006931084_0.7695097761939234","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@autolabz/service-auth-nextjs","version":"1.0.1","_id":"@autolabz/service-auth-nextjs@1.0.1","maintainers":[{"name":"autolabz","email":"mzhh@mzhh.xyz"}],"dist":{"shasum":"9da689b196ae29d8d6ae6ac0a268a4703b065578","tarball":"https://registry.npmjs.org/@autolabz/service-auth-nextjs/-/service-auth-nextjs-1.0.1.tgz","fileCount":8,"integrity":"sha512-SgXvXmFaUhDNtcHQu+oHcDUWmKSA8//x1QYqsG/FTJGvOHfznCr3LpQA2hsrDEbZGPCl4UdzEWTZSzzvYotBIQ==","signatures":[{"sig":"MEYCIQD1x6G5CPU5CfrIzg8zw3+ckJrS246+g8jXtZHOqlgAgAIhALbi9f9Rwn+xQ4OyLEJSza0GyZCDDv6+oGuYY/zXw99w","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":35679},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"7aaed46abb7b0c16716e887d0501aadcd4b00fa6","scripts":{"build":"npm run clean && tsup src/index.ts --format esm,cjs --dts --sourcemap --clean --target node18","clean":"rimraf dist","prepare":"npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"autolabz","email":"mzhh@mzhh.xyz"},"_npmVersion":"10.8.2","description":"Next.js App Router authentication utilities for AutoLab services","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"@autolabz/service-auth-core":"^1.0.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","rimraf":"^5.0.5","typescript":"^5.6.3"},"_npmOperationalInternal":{"tmp":"tmp/service-auth-nextjs_1.0.1_1763033935682_0.3890022409294265","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@autolabz/service-auth-nextjs","version":"1.0.2","_id":"@autolabz/service-auth-nextjs@1.0.2","maintainers":[{"name":"autolabz","email":"mzhh@mzhh.xyz"}],"dist":{"shasum":"adfc1565fd7e0e006d223f282dbdc061cf6feab9","tarball":"https://registry.npmjs.org/@autolabz/service-auth-nextjs/-/service-auth-nextjs-1.0.2.tgz","fileCount":8,"integrity":"sha512-IR6ZsqR06XgBDZh7XDlch5t4MMR7ozmAIbB6hRyJeQI33IlVHNNb/SIl5LyZ2OqugxvZDk6jsjAfh73rKWqRbQ==","signatures":[{"sig":"MEUCIDO3TPsQShYeG9Jy6SOCfCLeQn+gOr23B8yrv0Uitt50AiEA2SFB62lLeXXVofgMnCwC1rqk0QWoPqkAF28+1mi5PbY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":36719},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"gitHead":"2100f007a4759a2b8c9aeb2c2591efcf93d5346f","scripts":{"build":"npm run clean && tsup src/index.ts --format esm,cjs --dts --sourcemap --clean --target node18","clean":"rimraf dist","prepare":"npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"autolabz","email":"mzhh@mzhh.xyz"},"_npmVersion":"10.8.2","description":"Next.js App Router authentication utilities for AutoLab services","directories":{},"sideEffects":false,"_nodeVersion":"20.19.5","dependencies":{"@autolabz/service-auth-core":"^1.0.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","rimraf":"^5.0.5","typescript":"^5.6.3"},"_npmOperationalInternal":{"tmp":"tmp/service-auth-nextjs_1.0.2_1763371448210_0.020612880743095197","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@autolabz/service-auth-nextjs","version":"1.0.3","type":"module","description":"Next.js App Router authentication utilities for AutoLab services","sideEffects":false,"main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"dependencies":{"@autolabz/service-auth-core":"^1.0.1"},"devDependencies":{"rimraf":"^5.0.5","tsup":"^8.3.0","typescript":"^5.6.3"},"scripts":{"clean":"rimraf dist","build":"npm run clean && tsup src/index.ts --format esm,cjs --dts --sourcemap --clean --target node18","prepare":"npm run build","typecheck":"tsc -p tsconfig.json --noEmit"},"_id":"@autolabz/service-auth-nextjs@1.0.3","gitHead":"2100f007a4759a2b8c9aeb2c2591efcf93d5346f","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-G3cs9QOIcSjnuTQ5VuA5y46NBfc4onJatc6ov174zDo2KUk4xrgott1eUJGzNoZ9tBZPIAA0wlnL2SUvZ9jI9w==","shasum":"487a76424d5db793379d6881dd3e50baca67212e","tarball":"https://registry.npmjs.org/@autolabz/service-auth-nextjs/-/service-auth-nextjs-1.0.3.tgz","fileCount":8,"unpackedSize":36719,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGwA1aX/GaSxJJmxAUmp6NDF2T6mjtvC4rLPpRVUBQQAAiEA5CeOVpyEAm5CSW7TmrqU4N5qH3OtItAkV/4O1nN30go="}]},"_npmUser":{"name":"autolabz","email":"mzhh@mzhh.xyz"},"directories":{},"maintainers":[{"name":"autolabz","email":"mzhh@mzhh.xyz"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/service-auth-nextjs_1.0.3_1763372644822_0.34218191133788856"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-13T04:08:51.012Z","modified":"2025-11-17T09:44:05.246Z","1.0.0":"2025-11-13T04:08:51.251Z","1.0.1":"2025-11-13T11:38:55.885Z","1.0.2":"2025-11-17T09:24:08.426Z","1.0.3":"2025-11-17T09:44:05.017Z"},"description":"Next.js App Router authentication utilities for AutoLab services","maintainers":[{"name":"autolabz","email":"mzhh@mzhh.xyz"}],"readme":"# @autolabz/service-auth-nextjs\n\nNext.js App Router authentication utilities for AutoLab services.\n\n## Overview\n\nThis package provides authentication utilities specifically designed for Next.js App Router applications, built on the framework-agnostic `@autolabz/service-auth-core`. It offers:\n\n- **Request Verification**: Verify incoming requests using JWT or OAuth userinfo fallback\n- **Scope Validation**: Check for required scopes before processing requests\n- **AuthBridge Creation**: Generate AuthBridge objects for downstream SDK calls\n- **Type-Safe**: Full TypeScript support with discriminated union return types\n\n## Installation\n\n```bash\nnpm install @autolabz/service-auth-nextjs\n```\n\n## Quick Start\n\n### Basic Request Verification\n\n```typescript\nimport { verifyRequest, type AuthConfig } from '@autolabz/service-auth-nextjs';\n\nconst authConfig: AuthConfig = {\n  jwtAlg: 'HS256',\n  jwtAccessSecret: process.env.JWT_ACCESS_SECRET,\n  authBaseUrl: process.env.AUTH_BASE_URL!,\n  oauthUserinfoPath: '/oauth/userinfo',\n  oauthUserinfoTimeoutMs: 2000,\n};\n\n// In your API route (app/api/hello/route.ts)\nexport async function GET(request: Request) {\n  const result = await verifyRequest(request, authConfig);\n  \n  if (!result.success) {\n    return Response.json({ error: result.error }, { status: 401 });\n  }\n\n  return Response.json({\n    message: `Hello, ${result.auth.email || result.auth.userId}!`,\n  });\n}\n```\n\n### Request Verification with Scope Check\n\n```typescript\nimport { verifyRequestWithScopes } from '@autolabz/service-auth-nextjs';\n\nexport async function GET(request: Request) {\n  // Require both 'data' and 'points' scopes\n  const result = await verifyRequestWithScopes(request, authConfig, ['data', 'points']);\n  \n  if (!result.success) {\n    const status = result.error === 'Insufficient scopes' ? 403 : 401;\n    return Response.json({ error: result.error }, { status });\n  }\n\n  return Response.json({ userId: result.auth.userId });\n}\n```\n\n### Using with Downstream Services\n\n```typescript\nimport { verifyRequest, makeAuthBridge } from '@autolabz/service-auth-nextjs';\nimport { createDataClient } from '@autolabz/data-sdk';\nimport { createPointsClient } from '@autolabz/points-sdk';\nimport { createLLMClient } from '@autolabz/llmapi-sdk';\n\nexport async function GET(request: Request) {\n  // 1. Verify the request\n  const authResult = await verifyRequest(request, authConfig);\n  if (!authResult.success) {\n    return Response.json({ error: authResult.error }, { status: 401 });\n  }\n\n  // 2. Create AuthBridge for downstream calls\n  const auth = makeAuthBridge(request, {\n    onUnauthorized: () => console.error('Downstream service returned 401'),\n  });\n\n  // 3. Use with SDK clients\n  const dataClient = createDataClient({\n    baseURL: process.env.DATA_BASE_URL!,\n    auth,\n  });\n\n  const pointsClient = createPointsClient({\n    baseURL: process.env.POINTS_BASE_URL!,\n    auth,\n  });\n\n  // 4. Make authenticated requests\n  const [userData, balance] = await Promise.all([\n    dataClient.get(`/v1/data/user-profile`),\n    pointsClient.getMyBalance(),\n  ]);\n\n  return Response.json({ userData, balance });\n}\n```\n\n## API Reference\n\n### `verifyRequest(request: Request, config: AuthConfig): Promise<AuthResult>`\n\nVerify an incoming Next.js request using JWT verification (SIMPLE mode) with OAuth userinfo fallback.\n\n**Parameters:**\n- `request`: Next.js Request object (Web API Request)\n- `config`: Authentication configuration\n\n**Returns:** `AuthResult`\n- On success: `{ success: true, auth: AuthPayload }`\n- On failure: `{ success: false, error: string }`\n\n### `verifyRequestWithScopes(request: Request, config: AuthConfig, requiredScopes: string[]): Promise<AuthResult>`\n\nVerify a request and check for required scopes.\n\n**Parameters:**\n- `request`: Next.js Request object\n- `config`: Authentication configuration\n- `requiredScopes`: Array of required scope strings\n\n**Returns:** `AuthResult`\n- On success: `{ success: true, auth: AuthPayload }`\n- On failure: `{ success: false, error: string }` (error can be 'Insufficient scopes')\n\n### `makeAuthBridge(request: Request, options?: AuthBridgeOptions): AuthBridgeLike`\n\nCreate an AuthBridge from a Next.js Request for use with AutoLab SDK clients.\n\n**Parameters:**\n- `request`: Next.js Request object\n- `options`: Optional configuration\n  - `onUnauthorized?: () => void`: Callback when downstream service returns 401\n\n**Returns:** `AuthBridgeLike` object compatible with SDK clients\n\n## Configuration\n\n### `AuthConfig`\n\n```typescript\ninterface AuthConfig {\n  // JWT verification (SIMPLE mode)\n  jwtAlg: 'HS256' | 'RS256';\n  jwtAccessSecret?: string;        // Required for HS256\n  jwksUrl?: string;                 // Required for RS256\n  authIssuer?: string;              // Optional issuer validation\n\n  // OAuth userinfo fallback\n  authBaseUrl: string;              // OAuth service base URL\n  oauthUserinfoPath?: string;       // Default: 'oauth/userinfo'\n  oauthUserinfoTimeoutMs?: number;  // Default: 2000\n  oauthExpectedAudience?: string;   // Optional audience validation\n}\n```\n\n## Type Definitions\n\n### `AuthResult`\n\nDiscriminated union type for authentication results:\n\n```typescript\ntype AuthResult =\n  | { success: true; auth: AuthPayload }\n  | { success: false; error: string };\n```\n\n### `AuthPayload`\n\n```typescript\ninterface AuthPayload {\n  userId: string;\n  sub?: string;\n  email?: string;\n  iat?: number;\n  exp?: number;\n  iss?: string;\n  aud?: string | string[];\n  azp?: string;\n  scope?: string;\n  tokenType?: string;\n}\n```\n\n## Complete Example: API Route\n\n```typescript\n// app/api/data/[key]/route.ts\nimport { verifyRequestWithScopes, makeAuthBridge } from '@autolabz/service-auth-nextjs';\nimport { createDataClient } from '@autolabz/data-sdk';\n\nconst authConfig = {\n  jwtAlg: 'HS256' as const,\n  jwtAccessSecret: process.env.JWT_ACCESS_SECRET!,\n  authBaseUrl: process.env.AUTH_BASE_URL!,\n  oauthUserinfoPath: '/oauth/userinfo',\n  oauthUserinfoTimeoutMs: 2000,\n};\n\nexport async function GET(\n  request: Request,\n  { params }: { params: { key: string } }\n) {\n  // Verify with required scope\n  const result = await verifyRequestWithScopes(request, authConfig, ['data']);\n  \n  if (!result.success) {\n    const status = result.error === 'Insufficient scopes' ? 403 : 401;\n    return Response.json({ error: result.error }, { status });\n  }\n\n  // Create auth bridge for downstream call\n  const auth = makeAuthBridge(request);\n  const dataClient = createDataClient({\n    baseURL: process.env.DATA_BASE_URL!,\n    auth,\n  });\n\n  try {\n    const data = await dataClient.get(`/v1/data/${encodeURIComponent(params.key)}`);\n    return Response.json(data);\n  } catch (error) {\n    return Response.json(\n      { error: 'Failed to fetch data' },\n      { status: 500 }\n    );\n  }\n}\n\nexport async function PUT(\n  request: Request,\n  { params }: { params: { key: string } }\n) {\n  const result = await verifyRequestWithScopes(request, authConfig, ['data']);\n  \n  if (!result.success) {\n    const status = result.error === 'Insufficient scopes' ? 403 : 401;\n    return Response.json({ error: result.error }, { status });\n  }\n\n  const auth = makeAuthBridge(request);\n  const dataClient = createDataClient({\n    baseURL: process.env.DATA_BASE_URL!,\n    auth,\n  });\n\n  const body = await request.json();\n  \n  try {\n    await dataClient.put(`/v1/data/${encodeURIComponent(params.key)}`, body);\n    return Response.json({ success: true });\n  } catch (error) {\n    return Response.json(\n      { error: 'Failed to update data' },\n      { status: 500 }\n    );\n  }\n}\n```\n\n## Environment Variables\n\n```bash\n# JWT verification (SIMPLE mode)\nJWT_ALG=HS256\nJWT_ACCESS_SECRET=your-secret\n\n# OAuth userinfo fallback\nAUTH_BASE_URL=http://auth-service/api\nOAUTH_USERINFO_PATH=/oauth/userinfo\nOAUTH_USERINFO_TIMEOUT_MS=2000\n\n# Optional\nAUTH_ISSUER=https://auth.example.com\nOAUTH_EXPECTED_AUDIENCE=autolab-api\n\n# Downstream services\nDATA_BASE_URL=http://data-service\nPOINTS_BASE_URL=http://points-service\nLLMAPI_BASE_URL=http://llmapi-service\n```\n\n## Middleware Pattern\n\nFor route-wide authentication, you can create a middleware wrapper:\n\n```typescript\n// lib/auth-middleware.ts\nimport { verifyRequest, type AuthConfig, type AuthPayload } from '@autolabz/service-auth-nextjs';\n\nexport function withAuth(\n  handler: (request: Request, auth: AuthPayload, ...args: any[]) => Promise<Response>\n) {\n  return async (request: Request, ...args: any[]) => {\n    const authConfig: AuthConfig = {\n      jwtAlg: 'HS256',\n      jwtAccessSecret: process.env.JWT_ACCESS_SECRET!,\n      authBaseUrl: process.env.AUTH_BASE_URL!,\n    };\n\n    const result = await verifyRequest(request, authConfig);\n    \n    if (!result.success) {\n      return Response.json({ error: result.error }, { status: 401 });\n    }\n\n    return handler(request, result.auth, ...args);\n  };\n}\n\n// Usage in route\nexport const GET = withAuth(async (request, auth) => {\n  return Response.json({ userId: auth.userId });\n});\n```\n\n## Best Practices\n\n1. **Configuration**: Store `AuthConfig` in a central location and reuse across routes\n2. **Error Handling**: Always check `result.success` before accessing `result.auth`\n3. **Scope Validation**: Use `verifyRequestWithScopes` when endpoints require specific permissions\n4. **AuthBridge**: Create AuthBridge only after successful verification\n5. **Environment Variables**: Never hardcode secrets; use environment variables\n\n## Troubleshooting\n\n### 401 Unauthorized\n\n- Verify `AUTH_BASE_URL` and `OAUTH_USERINFO_PATH` are correct\n- Ensure request includes `Authorization: Bearer <token>` header\n- Check token validity and expiration\n\n### 403 Insufficient Scopes\n\n- Verify the token includes all required scopes\n- Check scope configuration in OAuth application settings\n\n### Request Timeout\n\n- Increase `oauthUserinfoTimeoutMs` value\n- Check auth service performance and network latency\n\n## License\n\nMIT\n\n","readmeFilename":"README.md"}