claudeinone-cli 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +16 -1
- package/kit/.claude/.ck.json +9 -0
- package/kit/.claude/.ckignore +12 -0
- package/kit/.claude/agents/accessibility-auditor.md +46 -0
- package/kit/.claude/agents/api-designer.md +43 -0
- package/kit/.claude/agents/backend-developer.md +54 -0
- package/kit/.claude/agents/brainstormer.md +33 -0
- package/kit/.claude/agents/campaign-manager.md +36 -0
- package/kit/.claude/agents/code-reviewer.md +39 -0
- package/kit/.claude/agents/content-creator.md +38 -0
- package/kit/.claude/agents/copywriter.md +42 -0
- package/kit/.claude/agents/database-admin.md +37 -0
- package/kit/.claude/agents/debugger.md +46 -0
- package/kit/.claude/agents/devops-engineer.md +41 -0
- package/kit/.claude/agents/docs-manager.md +33 -0
- package/kit/.claude/agents/email-wizard.md +40 -0
- package/kit/.claude/agents/frontend-developer.md +52 -0
- package/kit/.claude/agents/fullstack-developer.md +55 -0
- package/kit/.claude/agents/git-manager.md +40 -0
- package/kit/.claude/agents/i18n-specialist.md +46 -0
- package/kit/.claude/agents/integration-specialist.md +48 -0
- package/kit/.claude/agents/journal-writer.md +39 -0
- package/kit/.claude/agents/mcp-manager.md +57 -0
- package/kit/.claude/agents/mobile-developer.md +38 -0
- package/kit/.claude/agents/performance-optimizer.md +38 -0
- package/kit/.claude/agents/planner.md +56 -0
- package/kit/.claude/agents/project-manager.md +34 -0
- package/kit/.claude/agents/refactorer.md +43 -0
- package/kit/.claude/agents/researcher.md +45 -0
- package/kit/.claude/agents/risk-analyst.md +33 -0
- package/kit/.claude/agents/scalability-consultant.md +39 -0
- package/kit/.claude/agents/scout.md +25 -0
- package/kit/.claude/agents/security-auditor.md +42 -0
- package/kit/.claude/agents/seo-specialist.md +44 -0
- package/kit/.claude/agents/skill-creator.md +64 -0
- package/kit/.claude/agents/social-media-manager.md +35 -0
- package/kit/.claude/agents/systems-designer.md +35 -0
- package/kit/.claude/agents/technology-strategist.md +43 -0
- package/kit/.claude/agents/tester.md +40 -0
- package/kit/.claude/agents/ui-ux-designer.md +40 -0
- package/kit/.claude/commands/co/ask.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/co/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/co/bootstrap.md +31 -0
- package/kit/.claude/commands/co/brainstorm.md +27 -0
- package/kit/.claude/commands/co/campaign.md +28 -0
- package/kit/.claude/commands/co/changelog.md +25 -0
- package/kit/.claude/commands/co/checkpoint.md +25 -0
- package/kit/.claude/commands/co/ci.md +26 -0
- package/kit/.claude/commands/co/ck-help.md +24 -0
- package/kit/.claude/commands/co/coding-level.md +24 -0
- package/kit/.claude/commands/co/content-cro.md +26 -0
- package/kit/.claude/commands/co/content-enhance.md +26 -0
- package/kit/.claude/commands/co/content-fast.md +24 -0
- package/kit/.claude/commands/co/content-good.md +26 -0
- package/kit/.claude/commands/co/cook.md +33 -0
- package/kit/.claude/commands/co/debug.md +26 -0
- package/kit/.claude/commands/co/deploy.md +25 -0
- package/kit/.claude/commands/co/design-3d.md +27 -0
- package/kit/.claude/commands/co/design-describe.md +25 -0
- package/kit/.claude/commands/co/design-fast.md +25 -0
- package/kit/.claude/commands/co/design-good.md +28 -0
- package/kit/.claude/commands/co/design-screenshot.md +26 -0
- package/kit/.claude/commands/co/design-video.md +26 -0
- package/kit/.claude/commands/co/docker.md +24 -0
- package/kit/.claude/commands/co/docs-api.md +25 -0
- package/kit/.claude/commands/co/docs-init.md +26 -0
- package/kit/.claude/commands/co/docs-readme.md +24 -0
- package/kit/.claude/commands/co/docs-summarize.md +25 -0
- package/kit/.claude/commands/co/docs-update.md +25 -0
- package/kit/.claude/commands/co/env-check.md +25 -0
- package/kit/.claude/commands/co/fix-ci.md +29 -0
- package/kit/.claude/commands/co/fix-fast.md +28 -0
- package/kit/.claude/commands/co/fix-hard.md +33 -0
- package/kit/.claude/commands/co/fix-logs.md +28 -0
- package/kit/.claude/commands/co/fix-types.md +28 -0
- package/kit/.claude/commands/co/fix-ui.md +28 -0
- package/kit/.claude/commands/co/fix.md +27 -0
- package/kit/.claude/commands/co/git-cm.md +26 -0
- package/kit/.claude/commands/co/git-cp.md +26 -0
- package/kit/.claude/commands/co/git-pr.md +26 -0
- package/kit/.claude/commands/co/index.md +24 -0
- package/kit/.claude/commands/co/integrate-polar.md +29 -0
- package/kit/.claude/commands/co/integrate-sepay.md +29 -0
- package/kit/.claude/commands/co/journal.md +27 -0
- package/kit/.claude/commands/co/k8s.md +24 -0
- package/kit/.claude/commands/co/kanban.md +25 -0
- package/kit/.claude/commands/co/lint-fix.md +24 -0
- package/kit/.claude/commands/co/load.md +25 -0
- package/kit/.claude/commands/co/migrate.md +28 -0
- package/kit/.claude/commands/co/mock.md +26 -0
- package/kit/.claude/commands/co/mode.md +24 -0
- package/kit/.claude/commands/co/monitor.md +25 -0
- package/kit/.claude/commands/co/new-feature.md +27 -0
- package/kit/.claude/commands/co/optimize.md +26 -0
- package/kit/.claude/commands/co/plan-archive.md +24 -0
- package/kit/.claude/commands/co/plan-ci.md +28 -0
- package/kit/.claude/commands/co/plan-cro.md +27 -0
- package/kit/.claude/commands/co/plan-fast.md +24 -0
- package/kit/.claude/commands/co/plan-hard.md +27 -0
- package/kit/.claude/commands/co/plan-parallel.md +25 -0
- package/kit/.claude/commands/co/plan-two.md +29 -0
- package/kit/.claude/commands/co/plan-validate.md +27 -0
- package/kit/.claude/commands/co/plan.md +27 -0
- package/kit/.claude/commands/co/pr.md +25 -0
- package/kit/.claude/commands/co/preview.md +26 -0
- package/kit/.claude/commands/co/refactor.md +25 -0
- package/kit/.claude/commands/co/release.md +25 -0
- package/kit/.claude/commands/co/review-a11y.md +24 -0
- package/kit/.claude/commands/co/review-codebase-parallel.md +27 -0
- package/kit/.claude/commands/co/review-codebase.md +27 -0
- package/kit/.claude/commands/co/review-perf.md +24 -0
- package/kit/.claude/commands/co/review-security.md +25 -0
- package/kit/.claude/commands/co/scaffold.md +25 -0
- package/kit/.claude/commands/co/scout.md +26 -0
- package/kit/.claude/commands/co/secure.md +26 -0
- package/kit/.claude/commands/co/seed.md +25 -0
- package/kit/.claude/commands/co/seo-audit.md +24 -0
- package/kit/.claude/commands/co/seo-keywords.md +25 -0
- package/kit/.claude/commands/co/skill-create.md +29 -0
- package/kit/.claude/commands/co/skill-fix-logs.md +28 -0
- package/kit/.claude/commands/co/slide-create.md +24 -0
- package/kit/.claude/commands/co/spawn.md +24 -0
- package/kit/.claude/commands/co/terraform.md +24 -0
- package/kit/.claude/commands/co/test-gen.md +24 -0
- package/kit/.claude/commands/co/test-ui.md +27 -0
- package/kit/.claude/commands/co/test.md +26 -0
- package/kit/.claude/commands/co/use-mcp.md +25 -0
- package/kit/.claude/commands/co/video-script.md +25 -0
- package/kit/.claude/commands/co/watzup.md +25 -0
- package/kit/.claude/commands/co/worktree.md +25 -0
- package/kit/.claude/commands/co/write-blog.md +25 -0
- package/kit/.claude/commands/co/write-copy.md +24 -0
- package/kit/.claude/commands/co/write-email.md +25 -0
- package/kit/.claude/commands/content/content-cro.md +26 -0
- package/kit/.claude/commands/content/content-enhance.md +26 -0
- package/kit/.claude/commands/content/content-fast.md +24 -0
- package/kit/.claude/commands/content/content-good.md +26 -0
- package/kit/.claude/commands/content/enhance.md +26 -0
- package/kit/.claude/commands/content/good.md +26 -0
- package/kit/.claude/commands/core/ask.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/core/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/core/bootstrap.md +31 -0
- package/kit/.claude/commands/core/ck-help.md +24 -0
- package/kit/.claude/commands/core/coding-level.md +24 -0
- package/kit/.claude/commands/core/cook.md +33 -0
- package/kit/.claude/commands/core/debug.md +26 -0
- package/kit/.claude/commands/core/journal.md +27 -0
- package/kit/.claude/commands/core/kanban.md +25 -0
- package/kit/.claude/commands/core/preview.md +26 -0
- package/kit/.claude/commands/core/scout.md +26 -0
- package/kit/.claude/commands/core/test-ui.md +27 -0
- package/kit/.claude/commands/core/test.md +26 -0
- package/kit/.claude/commands/core/use-mcp.md +25 -0
- package/kit/.claude/commands/core/watzup.md +25 -0
- package/kit/.claude/commands/core/worktree.md +25 -0
- package/kit/.claude/commands/design/3d.md +27 -0
- package/kit/.claude/commands/design/design-3d.md +27 -0
- package/kit/.claude/commands/design/design-describe.md +25 -0
- package/kit/.claude/commands/design/design-fast.md +25 -0
- package/kit/.claude/commands/design/design-good.md +28 -0
- package/kit/.claude/commands/design/design-screenshot.md +26 -0
- package/kit/.claude/commands/design/design-video.md +26 -0
- package/kit/.claude/commands/design/good.md +28 -0
- package/kit/.claude/commands/design/video.md +26 -0
- package/kit/.claude/commands/docs/docs-init.md +26 -0
- package/kit/.claude/commands/docs/docs-summarize.md +25 -0
- package/kit/.claude/commands/docs/docs-update.md +25 -0
- package/kit/.claude/commands/docs/init.md +26 -0
- package/kit/.claude/commands/docs/summarize.md +25 -0
- package/kit/.claude/commands/fix/ci.md +29 -0
- package/kit/.claude/commands/fix/fast.md +28 -0
- package/kit/.claude/commands/fix/fix-ci.md +29 -0
- package/kit/.claude/commands/fix/fix-fast.md +28 -0
- package/kit/.claude/commands/fix/fix-hard.md +33 -0
- package/kit/.claude/commands/fix/fix-logs.md +28 -0
- package/kit/.claude/commands/fix/fix-types.md +28 -0
- package/kit/.claude/commands/fix/fix-ui.md +28 -0
- package/kit/.claude/commands/fix/hard.md +33 -0
- package/kit/.claude/commands/fix/logs.md +28 -0
- package/kit/.claude/commands/fix/types.md +28 -0
- package/kit/.claude/commands/fix/ui.md +28 -0
- package/kit/.claude/commands/git/cp.md +26 -0
- package/kit/.claude/commands/git/git-cm.md +26 -0
- package/kit/.claude/commands/git/git-cp.md +26 -0
- package/kit/.claude/commands/git/git-pr.md +26 -0
- package/kit/.claude/commands/integrate/integrate-polar.md +29 -0
- package/kit/.claude/commands/integrate/integrate-sepay.md +29 -0
- package/kit/.claude/commands/integrate/sepay.md +29 -0
- package/kit/.claude/commands/plan/ci.md +28 -0
- package/kit/.claude/commands/plan/cro.md +27 -0
- package/kit/.claude/commands/plan/hard.md +27 -0
- package/kit/.claude/commands/plan/plan-archive.md +24 -0
- package/kit/.claude/commands/plan/plan-ci.md +28 -0
- package/kit/.claude/commands/plan/plan-cro.md +27 -0
- package/kit/.claude/commands/plan/plan-fast.md +24 -0
- package/kit/.claude/commands/plan/plan-hard.md +27 -0
- package/kit/.claude/commands/plan/plan-parallel.md +25 -0
- package/kit/.claude/commands/plan/plan-two.md +29 -0
- package/kit/.claude/commands/plan/plan-validate.md +27 -0
- package/kit/.claude/commands/plan/plan.md +27 -0
- package/kit/.claude/commands/plan/validate.md +27 -0
- package/kit/.claude/commands/skill/fix-logs.md +28 -0
- package/kit/.claude/commands/skill/skill-create.md +29 -0
- package/kit/.claude/commands/skill/skill-fix-logs.md +28 -0
- package/kit/.claude/settings.json +16 -0
- package/kit/.claude/skills/ai-anthropic.md +100 -0
- package/kit/.claude/skills/ai-context-engineering.md +113 -0
- package/kit/.claude/skills/ai-gemini.md +152 -0
- package/kit/.claude/skills/ai-langchain.md +93 -0
- package/kit/.claude/skills/ai-llamaindex.md +179 -0
- package/kit/.claude/skills/ai-mcp-builder.md +101 -0
- package/kit/.claude/skills/ai-openai.md +250 -0
- package/kit/.claude/skills/ai-prompt-engineering.md +173 -0
- package/kit/.claude/skills/ai-rag.md +91 -0
- package/kit/.claude/skills/ai-vectordb.md +215 -0
- package/kit/.claude/skills/analytics-segment.md +161 -0
- package/kit/.claude/skills/api-caching.md +103 -0
- package/kit/.claude/skills/api-documentation.md +50 -0
- package/kit/.claude/skills/api-graphql.md +234 -0
- package/kit/.claude/skills/api-openapi.md +116 -0
- package/kit/.claude/skills/api-pagination-filtering.md +239 -0
- package/kit/.claude/skills/api-rate-limiting.md +179 -0
- package/kit/.claude/skills/api-rest-advanced.md +50 -0
- package/kit/.claude/skills/api-rest.md +217 -0
- package/kit/.claude/skills/api-trpc.md +173 -0
- package/kit/.claude/skills/api-versioning.md +70 -0
- package/kit/.claude/skills/api-webhooks.md +226 -0
- package/kit/.claude/skills/arch-clean-code.md +226 -0
- package/kit/.claude/skills/arch-clean.md +91 -0
- package/kit/.claude/skills/arch-cqrs.md +229 -0
- package/kit/.claude/skills/arch-ddd.md +85 -0
- package/kit/.claude/skills/arch-event-driven.md +189 -0
- package/kit/.claude/skills/arch-microservices.md +80 -0
- package/kit/.claude/skills/arch-monorepo.md +87 -0
- package/kit/.claude/skills/arch-multi-tenant.md +81 -0
- package/kit/.claude/skills/arch-serverless.md +86 -0
- package/kit/.claude/skills/auth-clerk.md +97 -0
- package/kit/.claude/skills/auth-jwt.md +143 -0
- package/kit/.claude/skills/auth-lucia.md +93 -0
- package/kit/.claude/skills/auth-nextauth.md +446 -0
- package/kit/.claude/skills/auth-oauth.md +208 -0
- package/kit/.claude/skills/auth-oauth2.md +110 -0
- package/kit/.claude/skills/auth-passkeys.md +109 -0
- package/kit/.claude/skills/auth-session.md +88 -0
- package/kit/.claude/skills/backend-dotnet.md +414 -0
- package/kit/.claude/skills/backend-express.md +129 -0
- package/kit/.claude/skills/backend-fastify.md +104 -0
- package/kit/.claude/skills/backend-go.md +205 -0
- package/kit/.claude/skills/backend-graphql.md +149 -0
- package/kit/.claude/skills/backend-grpc.md +382 -0
- package/kit/.claude/skills/backend-hono.md +95 -0
- package/kit/.claude/skills/backend-java-spring.md +198 -0
- package/kit/.claude/skills/backend-nodejs-express.md +165 -0
- package/kit/.claude/skills/backend-nodejs.md +143 -0
- package/kit/.claude/skills/backend-php-laravel.md +156 -0
- package/kit/.claude/skills/backend-python-django.md +200 -0
- package/kit/.claude/skills/backend-python-fastapi.md +169 -0
- package/kit/.claude/skills/backend-ruby-rails.md +190 -0
- package/kit/.claude/skills/backend-rust.md +182 -0
- package/kit/.claude/skills/backend-websockets.md +392 -0
- package/kit/.claude/skills/cache-redis.md +195 -0
- package/kit/.claude/skills/caching-strategies.md +100 -0
- package/kit/.claude/skills/cloud-aws.md +165 -0
- package/kit/.claude/skills/cloud-azure.md +187 -0
- package/kit/.claude/skills/cloud-cloudflare.md +74 -0
- package/kit/.claude/skills/cloud-fly.md +94 -0
- package/kit/.claude/skills/cloud-gcp.md +160 -0
- package/kit/.claude/skills/cloud-railway.md +92 -0
- package/kit/.claude/skills/cloud-render.md +70 -0
- package/kit/.claude/skills/cloud-serverless.md +68 -0
- package/kit/.claude/skills/cloud-vercel.md +76 -0
- package/kit/.claude/skills/component-patterns.md +50 -0
- package/kit/.claude/skills/content-management.md +197 -0
- package/kit/.claude/skills/cors-security.md +50 -0
- package/kit/.claude/skills/data-csv-excel.md +210 -0
- package/kit/.claude/skills/database-optimization.md +196 -0
- package/kit/.claude/skills/databases-transactions.md +68 -0
- package/kit/.claude/skills/db-cassandra.md +89 -0
- package/kit/.claude/skills/db-drizzle.md +363 -0
- package/kit/.claude/skills/db-dynamodb.md +83 -0
- package/kit/.claude/skills/db-elasticsearch.md +105 -0
- package/kit/.claude/skills/db-firebase-firestore.md +191 -0
- package/kit/.claude/skills/db-mongodb.md +198 -0
- package/kit/.claude/skills/db-mysql.md +50 -0
- package/kit/.claude/skills/db-neon.md +72 -0
- package/kit/.claude/skills/db-planetscale.md +76 -0
- package/kit/.claude/skills/db-postgresql.md +50 -0
- package/kit/.claude/skills/db-prisma.md +414 -0
- package/kit/.claude/skills/db-redis.md +50 -0
- package/kit/.claude/skills/db-sqlite.md +149 -0
- package/kit/.claude/skills/db-supabase.md +445 -0
- package/kit/.claude/skills/devops-ci-cd.md +271 -0
- package/kit/.claude/skills/devops-database-backup.md +77 -0
- package/kit/.claude/skills/devops-docker.md +93 -0
- package/kit/.claude/skills/devops-github-actions.md +82 -0
- package/kit/.claude/skills/devops-health-checks.md +50 -0
- package/kit/.claude/skills/devops-kubernetes.md +109 -0
- package/kit/.claude/skills/devops-logging.md +163 -0
- package/kit/.claude/skills/devops-monitoring.md +203 -0
- package/kit/.claude/skills/devops-pulumi.md +94 -0
- package/kit/.claude/skills/devops-secrets.md +166 -0
- package/kit/.claude/skills/devops-terraform.md +226 -0
- package/kit/.claude/skills/error-boundaries.md +84 -0
- package/kit/.claude/skills/file-storage.md +50 -0
- package/kit/.claude/skills/frontend-angular.md +104 -0
- package/kit/.claude/skills/frontend-astro.md +94 -0
- package/kit/.claude/skills/frontend-bundle-analysis.md +147 -0
- package/kit/.claude/skills/frontend-forms.md +134 -0
- package/kit/.claude/skills/frontend-htmx.md +86 -0
- package/kit/.claude/skills/frontend-nextjs.md +188 -0
- package/kit/.claude/skills/frontend-pwa.md +105 -0
- package/kit/.claude/skills/frontend-react-hooks.md +238 -0
- package/kit/.claude/skills/frontend-react.md +129 -0
- package/kit/.claude/skills/frontend-remix-advanced.md +106 -0
- package/kit/.claude/skills/frontend-remix.md +101 -0
- package/kit/.claude/skills/frontend-solid.md +99 -0
- package/kit/.claude/skills/frontend-state-management.md +134 -0
- package/kit/.claude/skills/frontend-state.md +106 -0
- package/kit/.claude/skills/frontend-svelte.md +121 -0
- package/kit/.claude/skills/frontend-testing.md +100 -0
- package/kit/.claude/skills/frontend-vite.md +94 -0
- package/kit/.claude/skills/frontend-vue.md +133 -0
- package/kit/.claude/skills/frontend-webpack.md +93 -0
- package/kit/.claude/skills/functional-programming.md +50 -0
- package/kit/.claude/skills/hooks-custom.md +50 -0
- package/kit/.claude/skills/http-server.md +50 -0
- package/kit/.claude/skills/i18n-general.md +89 -0
- package/kit/.claude/skills/i18n-localization.md +191 -0
- package/kit/.claude/skills/i18n-nextjs.md +127 -0
- package/kit/.claude/skills/infrastructure-docker-compose.md +77 -0
- package/kit/.claude/skills/infrastructure-serverless.md +177 -0
- package/kit/.claude/skills/jwt-tokens.md +50 -0
- package/kit/.claude/skills/logging-winston.md +106 -0
- package/kit/.claude/skills/messaging-kafka.md +102 -0
- package/kit/.claude/skills/messaging-rabbitmq.md +50 -0
- package/kit/.claude/skills/mobile-capacitor.md +109 -0
- package/kit/.claude/skills/mobile-expo.md +101 -0
- package/kit/.claude/skills/mobile-flutter.md +259 -0
- package/kit/.claude/skills/mobile-react-native.md +238 -0
- package/kit/.claude/skills/monitoring-apm.md +50 -0
- package/kit/.claude/skills/monitoring-error-tracking.md +217 -0
- package/kit/.claude/skills/nodejs-streams.md +168 -0
- package/kit/.claude/skills/oauth-integration.md +50 -0
- package/kit/.claude/skills/patterns-dependency-injection.md +218 -0
- package/kit/.claude/skills/patterns-factory-singleton.md +209 -0
- package/kit/.claude/skills/patterns-observer-pubsub.md +210 -0
- package/kit/.claude/skills/payment-lemonsqueezy.md +101 -0
- package/kit/.claude/skills/payment-square.md +178 -0
- package/kit/.claude/skills/payment-stripe.md +206 -0
- package/kit/.claude/skills/perf-bundle.md +100 -0
- package/kit/.claude/skills/perf-web-vitals.md +102 -0
- package/kit/.claude/skills/performance-database-connection-pooling.md +67 -0
- package/kit/.claude/skills/performance-metrics.md +73 -0
- package/kit/.claude/skills/performance-optimization.md +208 -0
- package/kit/.claude/skills/performance-web-vitals.md +169 -0
- package/kit/.claude/skills/rate-limiting.md +77 -0
- package/kit/.claude/skills/reactive-programming.md +50 -0
- package/kit/.claude/skills/realtime-database.md +50 -0
- package/kit/.claude/skills/realtime-subscriptions.md +218 -0
- package/kit/.claude/skills/saas-ab-testing.md +90 -0
- package/kit/.claude/skills/saas-analytics.md +113 -0
- package/kit/.claude/skills/saas-billing.md +106 -0
- package/kit/.claude/skills/saas-email.md +88 -0
- package/kit/.claude/skills/saas-feature-flags.md +83 -0
- package/kit/.claude/skills/saas-onboarding.md +96 -0
- package/kit/.claude/skills/saas-user-onboarding.md +207 -0
- package/kit/.claude/skills/security-encryption.md +216 -0
- package/kit/.claude/skills/security-owasp.md +212 -0
- package/kit/.claude/skills/security-secrets-rotation.md +64 -0
- package/kit/.claude/skills/seo-content.md +94 -0
- package/kit/.claude/skills/seo-technical.md +101 -0
- package/kit/.claude/skills/serverless-framework.md +151 -0
- package/kit/.claude/skills/sharding-scaling.md +50 -0
- package/kit/.claude/skills/styling-css-modules.md +219 -0
- package/kit/.claude/skills/styling-styled-components.md +206 -0
- package/kit/.claude/skills/styling-tailwind.md +206 -0
- package/kit/.claude/skills/test-e2e.md +86 -0
- package/kit/.claude/skills/test-integration.md +216 -0
- package/kit/.claude/skills/test-performance.md +162 -0
- package/kit/.claude/skills/test-tdd.md +170 -0
- package/kit/.claude/skills/test-unit.md +301 -0
- package/kit/.claude/skills/testing-accessibility.md +117 -0
- package/kit/.claude/skills/testing-contract.md +75 -0
- package/kit/.claude/skills/testing-e2e-advanced.md +50 -0
- package/kit/.claude/skills/testing-load-stress.md +79 -0
- package/kit/.claude/skills/testing-mutation.md +92 -0
- package/kit/.claude/skills/testing-snapshot.md +50 -0
- package/kit/.claude/skills/testing-vitest.md +172 -0
- package/kit/.claude/skills/tooling-biome.md +91 -0
- package/kit/.claude/skills/tooling-build-tools.md +166 -0
- package/kit/.claude/skills/tooling-bun.md +94 -0
- package/kit/.claude/skills/tooling-eslint.md +103 -0
- package/kit/.claude/skills/tooling-git.md +79 -0
- package/kit/.claude/skills/tooling-monorepo.md +162 -0
- package/kit/.claude/skills/tooling-testing-frameworks.md +207 -0
- package/kit/.claude/skills/tooling-typescript.md +156 -0
- package/kit/.claude/skills/ui-a11y.md +106 -0
- package/kit/.claude/skills/ui-framer.md +106 -0
- package/kit/.claude/skills/ui-gsap.md +102 -0
- package/kit/.claude/skills/ui-radix.md +82 -0
- package/kit/.claude/skills/ui-shadcn.md +463 -0
- package/kit/.claude/skills/ui-tailwind.md +98 -0
- package/kit/.claude/skills/ui-threejs.md +110 -0
- package/kit/.claude/skills/ui-tokens.md +97 -0
- package/kit/.claude/skills/utilities-date-time.md +170 -0
- package/kit/.claude/skills/validation-schemas.md +110 -0
- package/kit/.claude/skills/version-control-git.md +144 -0
- package/kit/.claude/skills/web-accessibility-wcag.md +102 -0
- package/kit/.claude/skills/web-astro.md +197 -0
- package/kit/.claude/skills/web-html-css.md +224 -0
- package/kit/.claude/skills/web-htmx.md +99 -0
- package/kit/.claude/skills/web-nextjs-advanced.md +202 -0
- package/kit/.claude/skills/web-remix.md +194 -0
- package/kit/.claude/skills/web-seo.md +99 -0
- package/kit/.claude/skills/web-svelte.md +234 -0
- package/kit/.claude/skills/websocket-server.md +50 -0
- package/kit/.claude/skills/writing-marketing.md +89 -0
- package/kit/.claude/skills/writing-technical.md +119 -0
- package/kit/CLAUDE.md +206 -0
- package/kit/README.md +150 -0
- package/kit/SKILLS_INDEX.md +188 -0
- package/kit/docs/README.md +3 -0
- package/kit/journals/README.md +3 -0
- package/kit/plans/README.md +3 -0
- package/package.json +3 -1
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
# NextAuth.js
|
|
2
|
+
|
|
3
|
+
Complete authentication solution for Next.js with built-in session management and OAuth support.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install next-auth
|
|
9
|
+
|
|
10
|
+
# Environment variables
|
|
11
|
+
NEXTAUTH_URL=http://localhost:3000
|
|
12
|
+
NEXTAUTH_SECRET=$(openssl rand -base64 32)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Basic Configuration (app/api/auth/[...nextauth]/route.ts)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import NextAuth from 'next-auth';
|
|
19
|
+
import GithubProvider from 'next-auth/providers/github';
|
|
20
|
+
import GoogleProvider from 'next-auth/providers/google';
|
|
21
|
+
import CredentialsProvider from 'next-auth/providers/credentials';
|
|
22
|
+
import { PrismaAdapter } from '@auth/prisma-adapter';
|
|
23
|
+
import { prisma } from '@/lib/prisma';
|
|
24
|
+
|
|
25
|
+
export const authOptions = {
|
|
26
|
+
adapter: PrismaAdapter(prisma),
|
|
27
|
+
providers: [
|
|
28
|
+
GithubProvider({
|
|
29
|
+
clientId: process.env.GITHUB_ID,
|
|
30
|
+
clientSecret: process.env.GITHUB_SECRET
|
|
31
|
+
}),
|
|
32
|
+
GoogleProvider({
|
|
33
|
+
clientId: process.env.GOOGLE_ID,
|
|
34
|
+
clientSecret: process.env.GOOGLE_SECRET
|
|
35
|
+
}),
|
|
36
|
+
CredentialsProvider({
|
|
37
|
+
name: 'Credentials',
|
|
38
|
+
credentials: {
|
|
39
|
+
email: { label: 'Email', type: 'email' },
|
|
40
|
+
password: { label: 'Password', type: 'password' }
|
|
41
|
+
},
|
|
42
|
+
async authorize(credentials) {
|
|
43
|
+
if (!credentials?.email || !credentials?.password) return null;
|
|
44
|
+
|
|
45
|
+
const user = await prisma.user.findUnique({
|
|
46
|
+
where: { email: credentials.email }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (!user) return null;
|
|
50
|
+
|
|
51
|
+
const isValid = await bcrypt.compare(credentials.password, user.password);
|
|
52
|
+
if (!isValid) return null;
|
|
53
|
+
|
|
54
|
+
return { id: user.id.toString(), email: user.email, name: user.name };
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
],
|
|
58
|
+
callbacks: {
|
|
59
|
+
// Include user.id in session
|
|
60
|
+
async session({ session, user }) {
|
|
61
|
+
session.user.id = user.id;
|
|
62
|
+
return session;
|
|
63
|
+
},
|
|
64
|
+
// Control which users can sign in
|
|
65
|
+
async signIn({ user, account, profile }) {
|
|
66
|
+
if (account?.provider === 'github') {
|
|
67
|
+
// Allow GitHub users
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
// Restrict credentials login to existing users
|
|
71
|
+
return !!user;
|
|
72
|
+
},
|
|
73
|
+
// Modify JWT token
|
|
74
|
+
async jwt({ token, user, account }) {
|
|
75
|
+
if (user) {
|
|
76
|
+
token.id = user.id;
|
|
77
|
+
}
|
|
78
|
+
if (account) {
|
|
79
|
+
token.accessToken = account.access_token;
|
|
80
|
+
}
|
|
81
|
+
return token;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
pages: {
|
|
85
|
+
signIn: '/login',
|
|
86
|
+
signOut: '/logout',
|
|
87
|
+
error: '/auth/error',
|
|
88
|
+
verifyRequest: '/auth/verify-request'
|
|
89
|
+
},
|
|
90
|
+
session: {
|
|
91
|
+
strategy: 'jwt', // or 'database'
|
|
92
|
+
maxAge: 30 * 24 * 60 * 60 // 30 days
|
|
93
|
+
},
|
|
94
|
+
debug: process.env.NODE_ENV === 'development'
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const handler = NextAuth(authOptions);
|
|
98
|
+
|
|
99
|
+
export { handler as GET, handler as POST };
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Get Session in Components
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
'use client';
|
|
106
|
+
|
|
107
|
+
import { useSession, signIn, signOut } from 'next-auth/react';
|
|
108
|
+
|
|
109
|
+
export function LoginButton() {
|
|
110
|
+
const { data: session } = useSession();
|
|
111
|
+
|
|
112
|
+
if (session) {
|
|
113
|
+
return (
|
|
114
|
+
<>
|
|
115
|
+
Signed in as {session.user.email} <br />
|
|
116
|
+
<button onClick={() => signOut()}>Sign out</button>
|
|
117
|
+
</>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return <button onClick={() => signIn()}>Sign in</button>;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Server-Side Session Access
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
// Route handler
|
|
129
|
+
import { getServerSession } from 'next-auth/next';
|
|
130
|
+
|
|
131
|
+
export async function GET(request: Request) {
|
|
132
|
+
const session = await getServerSession();
|
|
133
|
+
|
|
134
|
+
if (!session) {
|
|
135
|
+
return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return Response.json({ user: session.user });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Server Component
|
|
142
|
+
import { getServerSession } from 'next-auth/next';
|
|
143
|
+
|
|
144
|
+
export default async function Dashboard() {
|
|
145
|
+
const session = await getServerSession();
|
|
146
|
+
|
|
147
|
+
if (!session) {
|
|
148
|
+
redirect('/login');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return <div>Welcome {session.user.name}</div>;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Session Provider Wrapper
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// app/layout.tsx
|
|
159
|
+
'use client';
|
|
160
|
+
|
|
161
|
+
import { SessionProvider } from 'next-auth/react';
|
|
162
|
+
|
|
163
|
+
export default function RootLayout({
|
|
164
|
+
children
|
|
165
|
+
}: {
|
|
166
|
+
children: React.ReactNode;
|
|
167
|
+
}) {
|
|
168
|
+
return (
|
|
169
|
+
<html>
|
|
170
|
+
<body>
|
|
171
|
+
<SessionProvider>{children}</SessionProvider>
|
|
172
|
+
</body>
|
|
173
|
+
</html>
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Custom Sign In Page
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
// app/login/page.tsx
|
|
182
|
+
'use client';
|
|
183
|
+
|
|
184
|
+
import { signIn } from 'next-auth/react';
|
|
185
|
+
import { useRouter } from 'next/navigation';
|
|
186
|
+
import { useState } from 'react';
|
|
187
|
+
|
|
188
|
+
export default function LoginPage() {
|
|
189
|
+
const router = useRouter();
|
|
190
|
+
const [email, setEmail] = useState('');
|
|
191
|
+
const [password, setPassword] = useState('');
|
|
192
|
+
const [error, setError] = useState('');
|
|
193
|
+
|
|
194
|
+
async function handleSubmit(e: React.FormEvent) {
|
|
195
|
+
e.preventDefault();
|
|
196
|
+
|
|
197
|
+
const result = await signIn('credentials', {
|
|
198
|
+
email,
|
|
199
|
+
password,
|
|
200
|
+
redirect: false
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
if (result?.error) {
|
|
204
|
+
setError(result.error);
|
|
205
|
+
} else {
|
|
206
|
+
router.push('/dashboard');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<form onSubmit={handleSubmit}>
|
|
212
|
+
<input
|
|
213
|
+
type="email"
|
|
214
|
+
value={email}
|
|
215
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
216
|
+
placeholder="Email"
|
|
217
|
+
/>
|
|
218
|
+
<input
|
|
219
|
+
type="password"
|
|
220
|
+
value={password}
|
|
221
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
222
|
+
placeholder="Password"
|
|
223
|
+
/>
|
|
224
|
+
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
225
|
+
<button type="submit">Sign In</button>
|
|
226
|
+
|
|
227
|
+
<hr />
|
|
228
|
+
|
|
229
|
+
<button
|
|
230
|
+
type="button"
|
|
231
|
+
onClick={() => signIn('github')}
|
|
232
|
+
>
|
|
233
|
+
Sign in with GitHub
|
|
234
|
+
</button>
|
|
235
|
+
<button
|
|
236
|
+
type="button"
|
|
237
|
+
onClick={() => signIn('google')}
|
|
238
|
+
>
|
|
239
|
+
Sign in with Google
|
|
240
|
+
</button>
|
|
241
|
+
</form>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Protected Routes with Middleware
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// middleware.ts
|
|
250
|
+
import { withAuth } from 'next-auth/middleware';
|
|
251
|
+
|
|
252
|
+
export default withAuth(function middleware(req) {
|
|
253
|
+
// Add custom logic here if needed
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
export const config = {
|
|
257
|
+
matcher: ['/dashboard/:path*', '/admin/:path*']
|
|
258
|
+
};
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Email Sign-In (Magic Links)
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import EmailProvider from 'next-auth/providers/email';
|
|
265
|
+
import { PrismaAdapter } from '@auth/prisma-adapter';
|
|
266
|
+
|
|
267
|
+
export const authOptions = {
|
|
268
|
+
adapter: PrismaAdapter(prisma),
|
|
269
|
+
providers: [
|
|
270
|
+
EmailProvider({
|
|
271
|
+
server: {
|
|
272
|
+
host: process.env.EMAIL_SERVER_HOST,
|
|
273
|
+
port: parseInt(process.env.EMAIL_SERVER_PORT),
|
|
274
|
+
auth: {
|
|
275
|
+
user: process.env.EMAIL_SERVER_USER,
|
|
276
|
+
pass: process.env.EMAIL_SERVER_PASSWORD
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
from: process.env.EMAIL_FROM,
|
|
280
|
+
sendVerificationRequest: async ({ identifier, url, provider, theme }) => {
|
|
281
|
+
// Custom email sending logic
|
|
282
|
+
await sendCustomEmail(identifier, url);
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
]
|
|
286
|
+
};
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Custom User Model (Prisma)
|
|
290
|
+
|
|
291
|
+
```prisma
|
|
292
|
+
model User {
|
|
293
|
+
id String @id @default(cuid())
|
|
294
|
+
name String?
|
|
295
|
+
email String? @unique
|
|
296
|
+
emailVerified DateTime?
|
|
297
|
+
image String?
|
|
298
|
+
password String? // For credentials provider
|
|
299
|
+
|
|
300
|
+
role String @default("user") // Custom field
|
|
301
|
+
|
|
302
|
+
accounts Account[]
|
|
303
|
+
sessions Session[]
|
|
304
|
+
posts Post[]
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
model Account {
|
|
308
|
+
id String @id @default(cuid())
|
|
309
|
+
userId String
|
|
310
|
+
type String
|
|
311
|
+
provider String
|
|
312
|
+
providerAccountId String
|
|
313
|
+
refresh_token String? @db.Text
|
|
314
|
+
access_token String? @db.Text
|
|
315
|
+
expires_at Int?
|
|
316
|
+
token_type String?
|
|
317
|
+
scope String?
|
|
318
|
+
id_token String? @db.Text
|
|
319
|
+
session_state String?
|
|
320
|
+
|
|
321
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
322
|
+
|
|
323
|
+
@@unique([provider, providerAccountId])
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
model Session {
|
|
327
|
+
id String @id @default(cuid())
|
|
328
|
+
sessionToken String @unique
|
|
329
|
+
userId String
|
|
330
|
+
expires DateTime
|
|
331
|
+
|
|
332
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
model VerificationToken {
|
|
336
|
+
identifier String
|
|
337
|
+
token String @unique
|
|
338
|
+
expires DateTime
|
|
339
|
+
|
|
340
|
+
@@unique([identifier, token])
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Role-Based Access Control
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// lib/auth.ts
|
|
348
|
+
import { getServerSession } from 'next-auth/next';
|
|
349
|
+
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
|
|
350
|
+
|
|
351
|
+
export async function requireAuth(requiredRole?: string) {
|
|
352
|
+
const session = await getServerSession(authOptions);
|
|
353
|
+
|
|
354
|
+
if (!session) {
|
|
355
|
+
throw new Error('Unauthorized');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (requiredRole && session.user.role !== requiredRole) {
|
|
359
|
+
throw new Error('Forbidden');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return session;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Usage in route handler
|
|
366
|
+
import { requireAuth } from '@/lib/auth';
|
|
367
|
+
|
|
368
|
+
export async function POST(request: Request) {
|
|
369
|
+
const session = await requireAuth('admin');
|
|
370
|
+
|
|
371
|
+
// Admin-only logic
|
|
372
|
+
return Response.json({ success: true });
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Event Callbacks
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
export const authOptions = {
|
|
380
|
+
// ... other config
|
|
381
|
+
events: {
|
|
382
|
+
async signIn({ user, account, profile, isNewUser }) {
|
|
383
|
+
console.log(`User ${user.email} signed in`);
|
|
384
|
+
|
|
385
|
+
if (isNewUser) {
|
|
386
|
+
// Send welcome email
|
|
387
|
+
await sendWelcomeEmail(user.email);
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
async signOut({ token }) {
|
|
391
|
+
console.log(`User ${token.email} signed out`);
|
|
392
|
+
},
|
|
393
|
+
async session({ session, user, newSession, trigger }) {
|
|
394
|
+
// Called whenever session is checked
|
|
395
|
+
console.log('Session checked');
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
## Best Practices
|
|
402
|
+
|
|
403
|
+
✅ **Never commit NEXTAUTH_SECRET** - Use environment variables
|
|
404
|
+
✅ **Always use HTTPS in production** - Set NEXTAUTH_URL to https
|
|
405
|
+
✅ **Secure cookies** - Enabled by default in production
|
|
406
|
+
✅ **Custom credentials** - Always hash passwords with bcrypt
|
|
407
|
+
✅ **Session strategy** - Use JWT for stateless, database for sessions
|
|
408
|
+
✅ **CSRF protection** - Built-in protection enabled by default
|
|
409
|
+
✅ **Database safety** - Use PrismaAdapter for database session storage
|
|
410
|
+
|
|
411
|
+
## Common Patterns
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
// Check if user is admin
|
|
415
|
+
const isAdmin = session?.user?.role === 'admin';
|
|
416
|
+
|
|
417
|
+
// Redirect if not authenticated
|
|
418
|
+
if (!session) {
|
|
419
|
+
redirect('/login');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Use session in API route
|
|
423
|
+
const userId = session?.user?.id;
|
|
424
|
+
|
|
425
|
+
// Update session after changes
|
|
426
|
+
await useSession().update();
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## When to Use NextAuth
|
|
430
|
+
|
|
431
|
+
✅ Next.js projects needing authentication
|
|
432
|
+
✅ OAuth integration (GitHub, Google, etc.)
|
|
433
|
+
✅ Email sign-in with magic links
|
|
434
|
+
✅ Credential-based authentication
|
|
435
|
+
✅ Session management
|
|
436
|
+
|
|
437
|
+
❌ APIs without web interface
|
|
438
|
+
❌ Non-Next.js applications
|
|
439
|
+
❌ Ultra-simple projects (consider Auth0 instead)
|
|
440
|
+
|
|
441
|
+
## Resources
|
|
442
|
+
|
|
443
|
+
- [NextAuth.js Documentation](https://next-auth.js.org/)
|
|
444
|
+
- [NextAuth Providers](https://next-auth.js.org/providers/overview)
|
|
445
|
+
- [Prisma Adapter](https://authjs.dev/reference/adapter/prisma)
|
|
446
|
+
- [Database Session Strategy](https://next-auth.js.org/configuration/databases)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# OAuth 2.0 & OpenID Connect
|
|
2
|
+
|
|
3
|
+
Secure third-party authentication and authorization.
|
|
4
|
+
|
|
5
|
+
## OAuth 2.0 Flow
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Authorization Code Flow (most secure)
|
|
9
|
+
import express from 'express';
|
|
10
|
+
import { OAuth2Client } from 'google-auth-library';
|
|
11
|
+
|
|
12
|
+
const oauth2Client = new OAuth2Client(
|
|
13
|
+
process.env.GOOGLE_CLIENT_ID,
|
|
14
|
+
process.env.GOOGLE_CLIENT_SECRET,
|
|
15
|
+
process.env.GOOGLE_REDIRECT_URL
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
// Step 1: Generate authorization URL
|
|
19
|
+
app.get('/auth/google', (req, res) => {
|
|
20
|
+
const authUrl = oauth2Client.generateAuthUrl({
|
|
21
|
+
access_type: 'offline',
|
|
22
|
+
scope: ['openid', 'email', 'profile']
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
res.redirect(authUrl);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Step 2: Handle callback and exchange code for token
|
|
29
|
+
app.get('/auth/google/callback', async (req, res) => {
|
|
30
|
+
const { code } = req.query;
|
|
31
|
+
|
|
32
|
+
const { tokens } = await oauth2Client.getToken(code);
|
|
33
|
+
oauth2Client.setCredentials(tokens);
|
|
34
|
+
|
|
35
|
+
const userInfo = await oauth2Client.request({
|
|
36
|
+
url: 'https://www.googleapis.com/oauth2/v2/userinfo'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Create or update user
|
|
40
|
+
let user = await db.users.findByEmail(userInfo.data.email);
|
|
41
|
+
if (!user) {
|
|
42
|
+
user = await db.users.create({
|
|
43
|
+
email: userInfo.data.email,
|
|
44
|
+
name: userInfo.data.name,
|
|
45
|
+
googleId: userInfo.data.id
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Create session
|
|
50
|
+
req.session.userId = user.id;
|
|
51
|
+
res.redirect('/dashboard');
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## GitHub OAuth
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
// Simplified GitHub OAuth
|
|
59
|
+
app.get('/auth/github', (req, res) => {
|
|
60
|
+
const authUrl = `https://github.com/login/oauth/authorize?` +
|
|
61
|
+
`client_id=${process.env.GITHUB_CLIENT_ID}&` +
|
|
62
|
+
`redirect_uri=${process.env.GITHUB_REDIRECT_URL}&` +
|
|
63
|
+
`scope=user:email`;
|
|
64
|
+
|
|
65
|
+
res.redirect(authUrl);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
app.get('/auth/github/callback', async (req, res) => {
|
|
69
|
+
const { code } = req.query;
|
|
70
|
+
|
|
71
|
+
// Exchange code for token
|
|
72
|
+
const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
'Accept': 'application/json'
|
|
77
|
+
},
|
|
78
|
+
body: JSON.stringify({
|
|
79
|
+
client_id: process.env.GITHUB_CLIENT_ID,
|
|
80
|
+
client_secret: process.env.GITHUB_CLIENT_SECRET,
|
|
81
|
+
code
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const { access_token } = await tokenResponse.json();
|
|
86
|
+
|
|
87
|
+
// Get user info
|
|
88
|
+
const userResponse = await fetch('https://api.github.com/user', {
|
|
89
|
+
headers: { Authorization: `Bearer ${access_token}` }
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const user = await userResponse.json();
|
|
93
|
+
|
|
94
|
+
// Upsert user
|
|
95
|
+
const dbUser = await db.users.findOrCreate({
|
|
96
|
+
where: { githubId: user.id },
|
|
97
|
+
defaults: {
|
|
98
|
+
email: user.email,
|
|
99
|
+
name: user.name,
|
|
100
|
+
githubId: user.id,
|
|
101
|
+
avatar: user.avatar_url
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
req.session.userId = dbUser.id;
|
|
106
|
+
res.redirect('/dashboard');
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Token Management
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// Store and use tokens securely
|
|
114
|
+
async function storeTokens(userId: string, tokens: any) {
|
|
115
|
+
await db.userTokens.create({
|
|
116
|
+
userId,
|
|
117
|
+
accessToken: tokens.access_token,
|
|
118
|
+
refreshToken: tokens.refresh_token,
|
|
119
|
+
expiresAt: new Date(Date.now() + tokens.expires_in * 1000)
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Refresh expired token
|
|
124
|
+
async function getValidToken(userId: string) {
|
|
125
|
+
let tokenData = await db.userTokens.findOne({ userId });
|
|
126
|
+
|
|
127
|
+
if (tokenData.expiresAt < new Date()) {
|
|
128
|
+
// Token expired, refresh it
|
|
129
|
+
const newTokens = await oauth2Client.refreshAccessToken(
|
|
130
|
+
tokenData.refreshToken
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
await db.userTokens.update(userId, {
|
|
134
|
+
accessToken: newTokens.access_token,
|
|
135
|
+
expiresAt: new Date(Date.now() + newTokens.expires_in * 1000)
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
tokenData = await db.userTokens.findOne({ userId });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return tokenData.accessToken;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## OpenID Connect
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// OpenID Connect adds identity layer on top of OAuth 2.0
|
|
149
|
+
// Includes ID token with user claims
|
|
150
|
+
|
|
151
|
+
const idToken = jwt.verify(
|
|
152
|
+
tokens.id_token,
|
|
153
|
+
process.env.GOOGLE_CLIENT_SECRET
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
console.log({
|
|
157
|
+
sub: idToken.sub, // Subject (user ID)
|
|
158
|
+
email: idToken.email,
|
|
159
|
+
name: idToken.name,
|
|
160
|
+
picture: idToken.picture
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Security Considerations
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// Always use HTTPS
|
|
168
|
+
// Verify state parameter to prevent CSRF
|
|
169
|
+
app.get('/auth/google', (req, res) => {
|
|
170
|
+
const state = crypto.randomBytes(32).toString('hex');
|
|
171
|
+
|
|
172
|
+
// Store state in session
|
|
173
|
+
req.session.oauth_state = state;
|
|
174
|
+
|
|
175
|
+
const authUrl = oauth2Client.generateAuthUrl({
|
|
176
|
+
state,
|
|
177
|
+
access_type: 'offline',
|
|
178
|
+
scope: ['openid', 'email']
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
res.redirect(authUrl);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
app.get('/auth/google/callback', (req, res) => {
|
|
185
|
+
const { state, code } = req.query;
|
|
186
|
+
|
|
187
|
+
// Verify state
|
|
188
|
+
if (state !== req.session.oauth_state) {
|
|
189
|
+
return res.status(400).send('Invalid state parameter');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Continue with code exchange...
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Best Practices
|
|
197
|
+
|
|
198
|
+
✅ **Use HTTPS** - Encrypt in transit
|
|
199
|
+
✅ **Verify state** - Prevent CSRF attacks
|
|
200
|
+
✅ **Store tokens securely** - Use secure storage
|
|
201
|
+
✅ **Refresh tokens** - Use refresh tokens for long-lived access
|
|
202
|
+
✅ **Scope minimally** - Request only needed permissions
|
|
203
|
+
|
|
204
|
+
## Resources
|
|
205
|
+
|
|
206
|
+
- [OAuth 2.0 Spec](https://tools.ietf.org/html/rfc6749)
|
|
207
|
+
- [OpenID Connect](https://openid.net/connect/)
|
|
208
|
+
- [Auth0 Documentation](https://auth0.com/docs)
|