DEV Community

Cover image for How to authenticate a Spotify User in next.js 14 using NextAuth
Mat_dweb
Mat_dweb

Posted on

How to authenticate a Spotify User in next.js 14 using NextAuth

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:

npx create-next-app@latest
Enter fullscreen mode Exit fullscreen mode

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:

npm install
Enter fullscreen mode Exit fullscreen mode

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:

npm install next-auth
Enter fullscreen mode Exit fullscreen mode

Running the Local Instance

To see your project live and start editing it, use this command:

npm run dev
Enter fullscreen mode Exit fullscreen mode

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

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

Providing Redirect URIs

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://localhost:3000/api/auth/callback/spotify
Enter fullscreen mode Exit fullscreen mode

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.

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

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

SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

openssl rand -base64 32
Enter fullscreen mode Exit fullscreen mode

Here the link to the error in production: 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

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 };
Enter fullscreen mode Exit fullscreen mode

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

'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;
Enter fullscreen mode Exit fullscreen mode

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

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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

'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>
    )
  }
}

Enter fullscreen mode Exit fullscreen mode

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. 😎

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

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

'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>
    )
  }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)