How to authenticate a Spotify User in next.js 14 using NextAuth
Tags: spotifyapi, nextjs, nextauth, typescript
Published: 2024-06-09 22:08:00

In this article, we'll walk you through authenticating a user with their Spotify account in Next.js 14. This method is compatible with Next.js 13 as well, so you're covered! 🎉

We'll be using the Spotify Provider along with NextAuth, a powerful authentication library for Next.js applications. No worries if you're new to this; I'll guide you through each step! 😊

## Setting Up Next.js

First, let's create a new Next.js 14 project. Open your terminal and run the following command in the directory where you want to create your project:

```bash
npx create-next-app@latest
```

Follow the prompts to name your app. For this example, I'll be using TypeScript, but feel free to stick with JavaScript if you prefer.

Next, ensure all packages are installed by running:

```bash
npm install
```

### Installing NextAuth
Next, we need to install the NextAuth dependencies. NextAuth is an open-source authentication library for Next.js applications that makes it easy to add authentication to your project.

Run the following command to install NextAuth:

```bash
npm install next-auth
```

### Running the Local Instance
To see your project live and start editing it, use this command:

```bash
npm run dev
```

This will likely load your application at http://localhost:3000 in your browser.

## Spotify API credentials

To integrate Spotify authentication, you'll need to obtain API credentials from Spotify. Follow these steps to set it up:

### Accessing Spotify for Developers
1. Go to the Spotify for Developers page here: https://developer.spotify.com/ 

2. Log in with your Spotify account.
3. Navigate to the Spotify Developer Dashboard here: https://developer.spotify.com/dashboard

### Creating a New App
Click on "_Create App_" and fill out the form that appears. 

![Dashbaord Header next to "Create App" button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k54htov6i8inov9jbyxe.png)

This form requires details about your app, such as its name and description. Creating an app in the Spotify Developer Dashboard allows you to obtain the necessary credentials to interact with the Spotify API.

![Form screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/la2fo6v7vl88105u5cpv.png)


### Providing Redirect URIs

!["Redirect URI form field screenshot"](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8z45evepei40s5i5ufdr.png)


In the form, you'll need to specify the redirect URI for your application in the "Website" field. This is where Spotify will send the user after authentication. For local development, use the following URL:

```http
http://localhost:3000/api/auth/callback/spotify
```

> When you deploy your app, remember to update this URL and URIs using your production URL.


### Selecting Web API
Indicate that your app will be using the "_Web API_" by selecting this option in the form.

!["Which API/SDKs are you planning to use?" form field screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/drdztparjn7yeb8w07bg.png)


Click **"Save"** to create your app.



## Retrieving Spotify Credentials
After creating your app, Spotify will provide you with essential credentials: the `Client ID` and `Client Secret`. These credentials are crucial for interacting with the Spotify API. Take them from here: 

![Client Id & Client Secret example screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i96ppvmj2qak0rjthc1o.png)

### Setting Up Environment Variables
Go back to your Next.js project and create a `.env.local` file in the root directory **(not inside the src/ folder)**. Add your Spotify credentials to this file:

.env.local
```env
SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret
```

> **VERY IMPORTANT**
> If you deploy your app, you **MUST** provide two extra env variables. If you don't provide them, production will throw an error.

```
NEXTAUTH_URL=url_of_your_app
NEXTAUTH_SECRET=hash_key
```

> You can execute this command on your terminal to generate a `hash_key`

```
openssl rand -base64 32
```

Here the link to the error in production: [https://next-auth.js.org/configuration/options#secret](https://next-auth.js.org/configuration/options#secret )

## Setup Authentication with NextAuth
Now, let's configure authentication to seamlessly integrate the Spotify Provider with NextAuth technology, utilizing the Spotify API credentials stored in the `.env.local` file.

### Creating Authentication Routes

1. Inside your project directory **(whether it's src/ or not)**, create the following path `src/app/api/auth/[...nextauth]/`.
2. Create a file named `route.ts` in this directory.


### Configuration in route.ts
In the `route.ts` file, set up NextAuth to authenticate users with the `SpotifyProvider`. Additionally, include callbacks to retrieve the `refresh-token` from the session object for further functionality. Like this: 

route.ts
```javascript 
import NextAuth from "next-auth/next";
import { type NextAuthOptions } from "next-auth";
import SpotifyProvider from 'next-auth/providers/spotify';

const options: NextAuthOptions = {
    providers: [
        SpotifyProvider({
            authorization:
                'https://accounts.spotify.com/authorize?scope=user-read-email,playlist-read-private,playlist-modify-private,playlist-modify-public',
            clientId: process.env.SPOTIFY_CLIENT_ID || '',
            clientSecret: process.env.SPOTIFY_CLIENT_SECRET || '',
        }),
    ],
    callbacks: {
        async jwt({ token, account }) {
            if(account){
                token.access_token = account.access_token;
            }
            return token;
        },
        async session({ session, token }) {
            return {
                ...session,
                token
            };
        },
    }
}


const handler = NextAuth(options);


export { handler as GET, handler as POST };
```

## Wrap App in the Session Provider
The next step involves creating a `Session Provider Wrapper` to encompass the entire application with the authentication service.

### Creating AuthProvider Component
Create a file named `AuthProvider.tsx`.
In the `AuthProvider.tsx` file, use the provider to create an element that wraps its children. This component will later be added to the `layout.tsx` file inside the `<body>` tag to encompass the entire application.

AuthProvider.tsx

```javascript
'use client'
import React from 'react';
import { SessionProvider } from "next-auth/react";


function AuthProvider({ children }: { children: React.ReactNode }) {
  return (
    <SessionProvider>
      {children}
    </SessionProvider>
  )
}


export default AuthProvider;
```

### Implementation in layout.tsx
In the `layout.tsx` file, add the `AuthProvider.tsx` component to wrap the application. This approach is necessary for **client-side rendering**, as the provider should be in the `layout.tsx` document, which cannot utilize **client-side rendering** directly.

layout.tsx

```javascript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import AuthProvider from "./AuthProvider";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <AuthProvider>
          {children}
        </AuthProvider>
      </body>
    </html>
  );
}
```

This setup integrates the authentication service into the application by creating an external component (`AuthProvider.tsx`) for **client-side rendering** and then adding it to the `layout.tsx` file.

## Create the User Interface
Next, we'll develop the user interface, which could look something like this:

page.tsx

```javascript
'use client'
import { useSession } from "next-auth/react";
import { signIn, signOut } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  console.log(session);

  if (session) {
    return (
      <div className='p-6'>
        <p className='text-white font-normal text-xl mt-5 mb-2'>Signed In as</p>
        <span className='bold-txt'>{session?.user?.name}</span>
        <p className='opacity-70 mt-8 mb-5 underline cursor-pointer' onClick={() => signOut()}>Sign Out</p>
      </div>
    )
  } else {
    return (
        <button onClick={() => signIn()} className='shadow-primary w-56 h-16 rounded-xl bg-white border-0 text-black text-3xl active:scale-[0.99] m-6'>Sign In</button>
    )
  }
}

```

In the `page.tsx` file, we'll start by extracting the session object using the `useSession()` function, which, along with the `signIn()` and `signOut()` methods, is part of the NextAuth features. The session object provides us with user information from the authentication provider, in this case, Spotify. The `signIn()` and `signOut()` methods trigger the respective processes. By calling them, the authentication setup we've already configured will be executed.

If you've followed each step provided here, you shouldn't encounter any errors, and your project should successfully authenticate users with their Spotify accounts. 🥳

You can also check out an application that utilizes this exact same technologies [Jamming](https://jamming-sooty.vercel.app/). 😎

Ande here the Github repository for the code: [https://github.com/Matdweb/spotify-api-tutorial/tree/how-to-authenticate-a-spotify-user-in-next.js-14-using-next-auth](https://github.com/Matdweb/spotify-api-tutorial/tree/how-to-authenticate-a-spotify-user-in-next.js-14-using-next-auth)

>NOTE: 
>If you need a nice interface but have no time. I provide you with this code with a simple but smooth interface:

page.tsx

```javascript
'use client'
import { useSession } from "next-auth/react";
import Image from "next/image";
import { signIn, signOut } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  if (session) {
    return (
      <div className='max-w-[19rem] h-[22rem] rounded-[2rem] border-4 border-solid border-white flex justify-around items-center flex-col flex-nowrap mt-10 ml-10 mb-16'>
        <div className='mt-8 w-full flex flex-col flex-nowrap justify-around items-center'>
          <Image
            src={'https://spotiy-playlist-retriever-experimental.vercel.app/_next/static/media/user_img.6db01878.svg'}
            width={160}
            height={160}
            alt='Defualt user image'
          />
          <p className='text-white font-normal text-xl mt-5 mb-2'>Sign In as</p>
          <span className='bold-txt'>{session?.user?.name}</span>
        </div>
        <p className='opacity-70 mt-8 mb-5 underline cursor-pointer' onClick={() => signOut()}>Sign Out</p>
      </div>
    )
  } else {
    return (
      <div className='max-w-[19rem] h-80 rounded-[2rem] border-4 border-solid border-white flex justify-around items-center flex-col flex-nowrap mt-10 ml-10'>
        <Image
          src={'https://spotiy-playlist-retriever-experimental.vercel.app/_next/static/media/sad_emoji.41405e6f.svg'}
          width={160}
          height={150}
          alt='sad emoji'
        />
        <button onClick={() => signIn()} className='shadow-primary w-56 h-16 rounded-xl bg-white border-0 text-black text-3xl active:scale-[0.99]'>Sign In</button>
      </div>
    )
  }
}

```