Skip to content

Commit

Permalink
Next.js 14 & Supabase SSR (#278)
Browse files Browse the repository at this point in the history
* Update helpers.ts

Handle empty as well as missing env variables

* Update helpers.ts

Re-added comments

* Update helpers.ts

Reduced line length and restored chaining operators just in case there's a good reason for including them.

* Support propagating product deletion to DB

* initial

* Replace 'var' with 'const'

* add toast

* add password recovery

* fixes

* implement open PRs

* implement more PRs

* fix createOrRetrieveCustomer

* Give button a displayName for logging purposes

* Created a 'Card' ui component

* Remove deprecated supabase auth helpers and update
workflows for creating supabase client

* use latest stripe api version, remove payment type
constraint, change trial handling per stripe docs

* Replaced trial_end with trial_period_days

* Add signout as server action, move server calls

* Added toasts

* 'message' -> 'status' or 'error' in toast calls

* Removed ring focus from toasts container and
simplified some error message handling on the account page

* Remove obsolete NextJS config

* Update route.ts

Throw error if Stripe webhook secret is missing to prevent failure during compile

* Merged branch pr200 into dev

* Rolled back stripe API version change

* Allow stripe-js to use user's default API version

* Update dependencies to latest

* refactor supabase auth

* add magic link/otp auth

-update types

* Update package.json

* Implement half-working password recovery

* Added signup, password signin, password reset

* Updated dependencies

* Squashed commit of the following:

commit ddadebc
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Sun Dec 3 17:59:42 2023 -0500

    Updated dependencies

commit cfb1137
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Sun Dec 3 17:57:42 2023 -0500

    Added signup, password signin, password reset

commit 77f0724
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Fri Dec 1 13:00:09 2023 -0500

    Implement half-working password recovery

commit 89fb774
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 23:17:19 2023 -0500

    Update dependencies to latest

commit ac26a2e
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 23:03:12 2023 -0500

    Allow stripe-js to use user's default API version

commit e50fc43
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 22:12:34 2023 -0500

    Rolled back stripe API version change

commit 16a8e8a
Merge: 1b6dca8 4446b80
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 22:07:41 2023 -0500

    Merge branch 'stripe-checkout' into dev

commit 1b6dca8
Merge: f06fd3c d6667d0
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 21:45:44 2023 -0500

    Merge branch 'toasts' into dev

commit f06fd3c
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 21:42:06 2023 -0500

    Merged branch pr200 into dev

commit 3fc4962
Merge: ad95b6d 289bcea
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 21:37:07 2023 -0500

    merged supabase-auth branch

commit ad95b6d
Merge: 4fad338 1a0cd38
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Wed Nov 29 21:28:08 2023 -0500

    Merge pull request #5 from chriscarrollsmith/ui-refactor

    UI refactor

commit 4fad338
Merge: 4f5b603 2f9aa32
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Wed Nov 29 21:21:22 2023 -0500

    Merge pull request #3 from chriscarrollsmith/issue269

    Replace 'var' with 'const'

commit 4f5b603
Merge: c7867b2 1506472
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Wed Nov 29 21:19:01 2023 -0500

    Merge pull request #2 from chriscarrollsmith/issue170

    Issue170

commit 1506472
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Wed Nov 29 21:18:39 2023 -0500

    Update route.ts

    Throw error if Stripe webhook secret is missing to prevent failure during compile

commit d6667d0
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 19:39:42 2023 -0500

    Remove obsolete NextJS config

commit 1b41ef8
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 19:17:16 2023 -0500

    Removed ring focus from toasts container and
    simplified some error message handling on the account page

commit c57bf26
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 17:38:30 2023 -0500

    'message' -> 'status' or 'error' in toast calls

commit 41f6875
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 13:37:39 2023 -0500

    Added toasts

commit 289bcea
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Wed Nov 29 12:54:43 2023 -0500

    Add signout as server action, move server calls

commit 4446b80
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Tue Nov 28 21:40:57 2023 -0500

    Replaced trial_end with trial_period_days

commit 44b481a
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Tue Nov 28 21:02:39 2023 -0500

    use latest stripe api version, remove payment type
    constraint, change trial handling per stripe docs

commit 4b64f0b
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Tue Nov 28 20:14:33 2023 -0500

    Remove deprecated supabase auth helpers and update
    workflows for creating supabase client

commit 1a0cd38
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Tue Nov 28 16:23:46 2023 -0500

    Created a 'Card' ui component

commit a6644a3
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Tue Nov 28 12:30:30 2023 -0500

    Give button a displayName for logging purposes

commit 2f9aa32
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Mon Nov 27 18:45:01 2023 -0500

    Replace 'var' with 'const'

commit 2468bf2
Author: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Date:   Fri Nov 17 10:20:51 2023 -0500

    Support propagating product deletion to DB

commit 0b7597f
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Tue Nov 14 15:29:30 2023 -0500

    Update helpers.ts

    Reduced line length and restored chaining operators just in case there's a good reason for including them.

commit e679650
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Tue Nov 14 15:16:00 2023 -0500

    Update helpers.ts

    Re-added comments

commit fd3e0f2
Author: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Date:   Tue Nov 14 15:04:31 2023 -0500

    Update helpers.ts

    Handle empty as well as missing env variables

* API routes for the various auth pathways

* Updated dependencies

* Eliminated API endpoints

* Added simple switches in auth-helpers.ts to
control allowed signin methods

* Refactor/streamline createOrRetrieveCustomer

* getURL now takes a path argument and handles leading slashes

* Fixed bug that broke checkout session if trial period was not set

* Cascade user deletion through database
Add toast error handling to checkout and portal APIs
Fix bug that prevented email rate limit errors being logged

* Added full support for toast error handling when
creating customer portal link and checkout session

* repaired/improved Stripe webhook error handling
Added cascading user delete to supabase migrations

* - Added Suspense around Toaster per NextJS docs on `useSearchParams`
- Handled signup case where emails are disabled in Supabase

* Added package.json npm command for stripe fixtures

* Fixed mishandled magic link condition and handled default sign-in view with a cookie

* Handled edge case where user's preferredSignInView
cookie value is not an allowed viewType

* - gitignored some local dev files
- removed rendundant redirect in oauth callback
- added signin success toast for oauth

* - gitignored some local dev files
- removed some redundant redirects for oauth sign in
- added a success toast for oauth sign in

* Enhanced control of routing and redirects

- Added boolean toggle to control whether routing from sign-in page goes through server or client (because screen flickers with server-side routing)
- Added helper functions to construct toast redirect paths
- Refactored auth-helpers for modularity

* Deleted defunct Card components
Moved Pricing component to a component folder

* Toaster passes through additional searchParams\nDisable button after magic link requests

* Separated server and client Navbar components
(facilitates resource sharing and rehydration)

* Simplified sign-in redirect
(possible now that server and client are separated)

* Sorted stripe helpers into client and server files

* gitignore vscode workspace settings

* Replaced stripe checkout API with server action
Fixed bug in calculating trial end date

* Replace Stripe portal API with server action
Added some server side error logging

* Update middleware.ts

Co-authored-by: Jon Meyers <jonathon.d.meyers@gmail.com>

* Delete next.config.js

* Disable buttons while submitting, fix password reset bug

* - Separate client/server account functions
(Fixes bug that only occurs in prod)
- Generate error redirects on server side
(since Vercel doesn't expose the error object to the client)

* Fixed missing leading slash in error redirect
Allowed dynamic source path for stripe checkout

* bump packages

-comment out NEXT_PUBLIC_SITE_URL (easy to mess up in local dev, automatically substitutes localhost:3000)
-remove double /
-remove pnpm-lock (readme specifies npm or yarn)

* Add display index to Stripe fixtures

* Redirect to home page on successful signup
(Ensures that password autosave gets triggered)

* Set default trial period with a variable
Fix off-by-one calculation of trial period end date

* Updated dependencies
Moved checkout session redirect generation to server
(Since NextJS doesn't expose the error object on the client)

* Universally implement loading dots
Simplify/refactor Pricing component
Avoid leaking email addresses in toast

* Handle database migrations appropriately

* Added Supabase local development workflow
Updated prices table schema to reflect Stripe changes
Added robust RLS to users, customers, and subscriptions
Cascaded auth changes to users, customers, and subscriptions

* Script to link to supabase remote

* Fixed some bugs in link implementation

* Removed accidental redundant file

* Enable buttons when user is not logged in

* Fixed supabase:migrate command
(now migrates database schema changes from local to remote rather than the other way around

* Fixed AuthApiError that arises in testing
if logged in with cookie for user deleted from database

* Documented how to develop locally with Supabase

* bump again

- use turbo for local dev
- fix confirmation email status
- trim user input
- prevent user from updating to same name or email

* Ignore svg routes in middleware pattern matcher

* update dependencies, use turbo for local dev

* Correctly export Next Metadata

* fix regex on middleware matcher

* fix case on Next.js

* refactor cookies to helpers

* add prettier script

* cleanup and bump

- fix nextjs logo size on mobile
- fix logo cloud spacing on mobile
- fix navigation buttons not showing on mobile
- bump packages
- improve sign in wording clarity
- drop name requirement on sign up (supabase will collect the name data if the user runs the schema sql)
- re-add schema.sql (why was this dropped?)
- add trimming to form data

---------

Co-authored-by: Christopher Carroll Smith <75859865+chriscarrollsmith@users.noreply.github.com>
Co-authored-by: Christopher Carroll Smith <chriscarrollsmith@gmail.com>
Co-authored-by: Jon Meyers <jonathon.d.meyers@gmail.com>
  • Loading branch information
4 people authored Feb 12, 2024
1 parent c7867b2 commit a138bf7
Show file tree
Hide file tree
Showing 74 changed files with 6,430 additions and 3,352 deletions.
13 changes: 9 additions & 4 deletions .env.local.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# Update these with your Supabase details from your project settings > API
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
# Update these with the details of your local test instance from the Supabase CLI
# ("API URL", "anon key", and "service_role key")
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=

# Update these with the details of your remote database
SUPABASE_PROJECT_REF=
SUPABASE_DB_PASSWORD=

# Update these with your Stripe credentials from https://dashboard.stripe.com/apikeys
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_1234
STRIPE_SECRET_KEY=sk_test_1234
STRIPE_WEBHOOK_SECRET=whsec_1234

# Update this with your stable site URL only for the production environment.
NEXT_PUBLIC_SITE_URL=https://your-deployment-url.vercel.app
# Add NEXT_PUBLIC_SITE_URL to your Vercel environmental variables for the production environment following the example below. This defaults to http://localhost:3000 in development.
# NEXT_PUBLIC_SITE_URL=https://your-deployment-url.vercel.app
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ yarn-error.log*

# editors
.vscode

# certificates
certificates
13 changes: 13 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Build artifacts
.next/
.turbo/
_next/
__tmp__/
dist/
node_modules/
target/
compiled/

pnpm-lock.yaml

types_db.ts
6 changes: 6 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"arrowParens": "always",
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none"
}
61 changes: 49 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ When deploying this template, the sequence of steps is important. Follow the ste

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments&env=NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,STRIPE_SECRET_KEY&envDescription=Enter%20your%20Stripe%20API%20keys.&envLink=https%3A%2F%2Fdashboard.stripe.com%2Fapikeys&project-name=nextjs-subscription-payments&repository-name=nextjs-subscription-payments&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnextjs-subscription-payments%2Ftree%2Fmain)

The Vercel Deployment will create a new repository with this template on your GitHub account and guide your through a new Supabase project creation. The [Supabase Vercel Deploy Integration](https://vercel.com/integrations/supabase-v2) will set up the necessary Supabase environment variables and run the [SQL migrations](./supabase/migrations/20230530034630_init.sql) to set up the Database schema on your account. You can inspect the created tables in your project's [Table editor](https://app.supabase.com/project/_/editor).
The Vercel Deployment will create a new repository with this template on your GitHub account and guide you through a new Supabase project creation. The [Supabase Vercel Deploy Integration](https://vercel.com/integrations/supabase-v2) will set up the necessary Supabase environment variables and run the [SQL migrations](./supabase/migrations/20230530034630_init.sql) to set up the Database schema on your account. You can inspect the created tables in your project's [Table editor](https://app.supabase.com/project/_/editor).

Should the automatic setup fail, please [create a Supabase account](https://app.supabase.com/projects), and a new project if needed. In your project, navigate to the [SQL editor](https://app.supabase.com/project/_/sql) and select the "Stripe Subscriptions" starter template from the Quick start section.

### Configure Auth

Follow [this guide](https://supabase.com/docs/guides/auth/social-login/auth-github) to set up an OAuth app with GitHub and configure Supabase to use it as an auth provider.

In your Supabase project, navigate to [auth > URL configuration](https://app.supabase.com/project/_/auth/url-configuration) and set your main production URL (e.g. https://your-deployment-url.vercel.app) as the site url.

Next, in your Vercel deployment settings, add a new **Production** environment variable called `NEXT_PUBLIC_SITE_URL` and set it to the same URL. Make sure to deselect preview and development environments to make sure that preview branches and local development work correctly.
Expand All @@ -45,9 +47,9 @@ If you've deployed this template via the "Deploy to Vercel" button above, you ca

Otherwise, for auth redirects (email confirmations, magic links, OAuth providers) to work correctly in deploy previews, navigate to the [auth settings](https://app.supabase.com/project/_/auth/url-configuration) and add the following wildcard URL to "Redirect URLs": `https://*-username.vercel.app/**`. You can read more about redirect wildcard patterns in the [docs](https://supabase.com/docs/guides/auth#redirect-urls-and-wildcards).

#### [Optional] - Set up OAuth providers
If you've deployed this template via the "Deploy to Vercel" button above, you can skip this step. The Supabase Vercel Integration will have run database migrations for you. You can check this by going to [the Table Editor for your Supabase project](https://supabase.com/dashboard/project/_/editor), and confirming there are tables with seed data.

You can use third-party login providers like GitHub or Google. Refer to the [docs](https://supabase.io/docs/guides/auth#third-party-logins) to learn how to configure these. Once configured, you can add them to the `provider` array of the [`Auth` component](./app/signin/AuthUI.tsx) page.
Otherwise, navigate to the [SQL Editor](https://supabase.com/dashboard/project/_/sql/new), paste the contents of [the Supabase `schema.sql` file](./schema.sql), and click RUN to initialize the database.

#### [Maybe Optional] - Set up Supabase environment variables (not needed if you installed via the Deploy Button)

Expand Down Expand Up @@ -122,15 +124,51 @@ vercel login
vercel link
```

### Setting up the env vars locally

Use the Vercel CLI to download the development env vars:
If you don't intend to use a local Supabase instance for development and testing, you can use the Vercel CLI to download the development env vars:

```bash
vercel env pull .env.local
```

Running this command will create a new `.env.local` file in your project folder. For security purposes, you will need to set the `SUPABASE_SERVICE_ROLE_KEY` manually from your [Supabase dashboard](https://app.supabase.io/) (`Settings > API`).
Running this command will create a new `.env.local` file in your project folder. For security purposes, you will need to set the `SUPABASE_SERVICE_ROLE_KEY` manually from your [Supabase dashboard](https://app.supabase.io/) (`Settings > API`). If you are not using a local Supabase instance, you should also change the `--local` flag to `--remote` in the `supabase:generate-types` script in `package.json`.

### Local development with Supabase

It's highly recommended to use a local Supabase instance for development and testing. We have provided a set of custom commands for this in `package.json`.

First, you will need to install [Docker](https://www.docker.com/get-started/). You should also copy `.env.local.example` to `.env.local`.

Next, run the following command to start a local Supabase instance and run the migrations to set up the database schema:

```bash
# or `npm` or `yarn` instead of `pnpm`
pnpm run supabase:start
```

The terminal output will provide you with values for the environment variables `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`, and `SUPABASE_SERVICE_ROLE_KEY`. Copy these into your `.env.local` file.

The terminal output will also provide you with a URL to access the local Supabase Studio, where you can make changes to your local database instance. (You can always find the Supabase Studio later by opening up a Docker window, navigating to `Containers` tab, and clicking the link in the `Ports` column for the corresponding container.)

To link your local Supabase instance to your project, you will need to set `SUPABASE_PROJECT_REF` and `SUPABASE_DB_PASSWORD` for your remote database in your `.env.local` file. You can find these values in the [Supabase dashboard](https://supabase.com/dashboard/projects) for your project. Then, run the following command to link your local Supabase instance to your project:

```bash
pnpm run supabase:link
```

Once you've linked your project, you can make changes to the database schema in your local Supabase Studio and run the following command to generate TypeScript types to match your schema:

```bash
pnpm run supabase:generate-types
```

You can also automatically generate a migration file with all the changes you've made to your local database schema and then push the migration to your remote database with the following commands:

```bash
pnpm run supabase:generate-migration
pnpm run supabase:migrate
```

Remember to test your changes thoroughly in your local environment before deploying them to production!

### Use the Stripe CLI to test webhooks

Expand All @@ -142,13 +180,16 @@ Next, start local webhook forwarding:
stripe listen --forward-to=localhost:3000/api/webhooks
```

Running this Stripe command will print a webhook secret (such as, `whsec_***`) to the console. Set `STRIPE_WEBHOOK_SECRET` to this value in your `.env.local` file.
Running this Stripe command will print a webhook secret (such as, `whsec_***`) to the console. Set `STRIPE_WEBHOOK_SECRET` to this value in your `.env.local` file. If you haven't already, you should also set `NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY` and `STRIPE_SECRET_KEY` in your `.env.local` file using the **test mode**(!) keys from your Stripe dashboard.

### Install dependencies and run the Next.js client

In a separate terminal, run the following commands to install dependencies and start the development server:

```bash
pnpm install
pnpm run dev
# or
npm install
npm run dev
# or
Expand All @@ -175,7 +216,3 @@ To run the project in live mode and process payments with Stripe, switch Stripe
Afterward, you will need to rebuild your production deployment for the changes to take effect. Within your project Dashboard, navigate to the "Deployments" tab, select the most recent deployment, click the overflow menu button (next to the "Visit" button) and select "Redeploy" (do NOT enable the "Use existing Build Cache" option).

To verify you are running in production mode, test checking out with the [Stripe test card](https://stripe.com/docs/testing). The test card should not work.

## A note on reliability

This template mirrors completed Stripe transactions to the Supabase database. This means that if the Supabase database is unavailable, the Stripe transaction will still succeed, but the Supabase database will not be updated, and the application will pass an error code back to Stripe. [By default](https://stripe.com/docs/webhooks/best-practices), Stripe will retry sending its response to the webhook for up to three days, or until the database update succeeds. This means that the Stripe transaction will eventually be reflected in the Supabase database as long as the database comes back online within three days. You may want to implement a process to automatically reconcile the Supabase database with Stripe in case of a prolonged outage.
38 changes: 0 additions & 38 deletions app/account/ManageSubscriptionButton.tsx

This file was deleted.

Loading

0 comments on commit a138bf7

Please sign in to comment.