Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

refactor: improve initial setup and configuration #64

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
refactor: improve initial setup and configuration
- Update .env.example with better organization and documentation
- Add clear sections for required and optional environment variables
- Update Stripe integration configuration and related files
- Update env.mjs to enforce required environment variables
- Update auth.config.ts to bypass auth in development if provider is not configured
- Update README with clearer setup instructions
  • Loading branch information
mrdorianh committed Nov 8, 2024
commit 58293855844085bbeb76566f45574918218e1bae
47 changes: 26 additions & 21 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
# -----------------------------------------------------------------------------
# App - Don't add "/" in the end of the url (same in production)
# Required Environment Variables
# -----------------------------------------------------------------------------
NEXT_PUBLIC_APP_URL=http://localhost:3000

# -----------------------------------------------------------------------------
# Authentication (NextAuth.js)
# -----------------------------------------------------------------------------
AUTH_SECRET=
# App - Don't add "/" in the end of the url (same in production)
NEXT_PUBLIC_APP_URL="http://localhost:3000"

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# Database (PostgreSQL - Neon DB)
DATABASE_URL='postgres://[user]:[password]@[neon_hostname]/[dbname]?sslmode=require'

GITHUB_OAUTH_TOKEN=
# Auth secret for token encryption. Generate one using `npx auth secret` or `openssl rand -base64 33`.
AUTH_SECRET=""

# -----------------------------------------------------------------------------
# Database (MySQL - Neon DB)
# Optional Authentication (NextAuth.js)
# -----------------------------------------------------------------------------
DATABASE_URL='postgres://[user]:[password]@[neon_hostname]/[dbname]?sslmode=require'
# Required only if you want authentication
# GOOGLE_CLIENT_ID=""
# GOOGLE_CLIENT_SECRET=""
# GITHUB_OAUTH_TOKEN=""


# -----------------------------------------------------------------------------
# Email (Resend)
# Optional Email (Resend)
# -----------------------------------------------------------------------------
RESEND_API_KEY=
EMAIL_FROM="SaaS Starter App <onboarding@resend.dev>"
# Required only if you want email features
# RESEND_API_KEY=""
# EMAIL_FROM="SaaS Starter App <onboarding@resend.dev>"


# -----------------------------------------------------------------------------
# Subscriptions (Stripe)
# Optional Subscriptions (Stripe)
# -----------------------------------------------------------------------------
STRIPE_API_KEY=
STRIPE_WEBHOOK_SECRET=
# Required only if you want payment features
# STRIPE_API_KEY=""
# STRIPE_WEBHOOK_SECRET=""

NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID=
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID=
# NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID=""
# NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID=""

NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID=
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID=
# NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID=""
# NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID=""
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -53,6 +53,48 @@ pnpm install
```sh
cp .env.example .env.local
```
>
> #### Where to get each of these environment variables:
>
> 1. **AUTH_SECRET**
> - Generate a random string using `openssl rand -base64 32` in terminal
> - Or use any secure random string generator
>
> 2. **Google OAuth Credentials (GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)**
> - Go to [Google Cloud Console](https://console.cloud.google.com/)
> - Create a new project
> - Enable Google OAuth API
> - Create OAuth 2.0 credentials
> - Set authorized redirect URI to `http://localhost:3000/api/auth/callback/google`
>
> 3. **GITHUB_OAUTH_TOKEN**
> - Go to [GitHub Settings > Developer Settings](https://github.com/settings/tokens)
> - Generate new Personal Access Token
> - Select required scopes
>
> 4. **DATABASE_URL**
> - # at [Neon](https://neon.tech)
> - Create a new project
> - Get connection string from dashboard
> - Replace `[user]`, `[password]`, `[neon_hostname]`, and `[dbname]` with your values
>
> 5. **RESEND_API_KEY**
> - # at [Resend](https://resend.com)
> - Get API key from dashboard
> - Update EMAIL_FROM with your verified domain (or use the default for testing)
>
> 6. **Stripe Variables**
> - # for [Stripe](https://stripe.com)
> - Get API key from dashboard (STRIPE_API_KEY)
> - Set up webhook in Stripe dashboard to get STRIPE_WEBHOOK_SECRET
> - Create products/prices in Stripe dashboard to get plan IDs:
> - NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID
> - NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID
> - NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID
> - NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID
>
> Remember to use test keys during development and switch to production keys when deploying.
>

3. Start the development server:

4 changes: 4 additions & 0 deletions actions/generate-user-stripe.ts
Original file line number Diff line number Diff line change
@@ -15,6 +15,10 @@ export type responseAction = {
const billingUrl = absoluteUrl("/#")

export async function generateUserStripe(priceId: string): Promise<responseAction> {
if (!stripe) {
throw new Error("Stripe is not configured");
}

let redirectUrl: string = "";

try {
4 changes: 4 additions & 0 deletions app/api/webhooks/stripe/route.ts
Original file line number Diff line number Diff line change
@@ -6,6 +6,10 @@ import { prisma } from "@/lib/db";
import { stripe } from "@/lib/stripe";

export async function POST(req: Request) {
if (!stripe || !env.STRIPE_WEBHOOK_SECRET) {
return new Response("Stripe is not configured", { status: 400 });
}

const body = await req.text();
const signature = headers().get("Stripe-Signature") as string;

28 changes: 18 additions & 10 deletions auth.config.ts
Original file line number Diff line number Diff line change
@@ -3,18 +3,26 @@ import Google from "next-auth/providers/google";
import Resend from "next-auth/providers/resend";

import { env } from "@/env.mjs";
import { sendVerificationRequest } from "@/lib/email";

export default {
providers: [
Google({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
Resend({
apiKey: env.RESEND_API_KEY,
from: env.EMAIL_FROM,
// sendVerificationRequest,
}),
// Only add Google provider if credentials are present
...(env.GOOGLE_CLIENT_ID && env.GOOGLE_CLIENT_SECRET
? [
Google({
clientId: env.GOOGLE_CLIENT_ID,
clientSecret: env.GOOGLE_CLIENT_SECRET,
}),
]
: []),
// Only add Resend provider if credentials are present
...(env.RESEND_API_KEY && env.EMAIL_FROM
? [
Resend({
apiKey: env.RESEND_API_KEY,
from: env.EMAIL_FROM,
}),
]
: []),
],
} satisfies NextAuthConfig;
22 changes: 11 additions & 11 deletions env.mjs
Original file line number Diff line number Diff line change
@@ -7,21 +7,21 @@ export const env = createEnv({
// See https://next-auth.js.org/deployment.
NEXTAUTH_URL: z.string().url().optional(),
AUTH_SECRET: z.string().min(1),
GOOGLE_CLIENT_ID: z.string().min(1),
GOOGLE_CLIENT_SECRET: z.string().min(1),
GITHUB_OAUTH_TOKEN: z.string().min(1),
GOOGLE_CLIENT_ID: z.string().optional(),
GOOGLE_CLIENT_SECRET: z.string().optional(),
GITHUB_OAUTH_TOKEN: z.string().optional(),
DATABASE_URL: z.string().min(1),
RESEND_API_KEY: z.string().min(1),
EMAIL_FROM: z.string().min(1),
STRIPE_API_KEY: z.string().min(1),
STRIPE_WEBHOOK_SECRET: z.string().min(1),
RESEND_API_KEY: z.string().optional(),
EMAIL_FROM: z.string().optional(),
STRIPE_API_KEY: z.string().optional(),
STRIPE_WEBHOOK_SECRET: z.string().optional(),
},
client: {
NEXT_PUBLIC_APP_URL: z.string().min(1),
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID: z.string().min(1),
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID: z.string().optional(),
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_ID: z.string().optional(),
NEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID: z.string().optional(),
NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID: z.string().optional(),
},
runtimeEnv: {
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
13 changes: 8 additions & 5 deletions lib/stripe.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Stripe from "stripe"

import { env } from "@/env.mjs"

export const stripe = new Stripe(env.STRIPE_API_KEY, {
apiVersion: "2024-04-10",
typescript: true,
})
export let stripe: Stripe | null = null;

if (env.STRIPE_API_KEY) {
stripe = new Stripe(env.STRIPE_API_KEY, {
apiVersion: "2024-04-10",
typescript: true,
});
}