Series: Project Spotiviz
Tags: #nextjs #webdev #tutorial #security
http://googleusercontent.com/image_generation_content/0
π The "Why."
We all love Spotify Wrapped. It is a brilliant piece of product marketing that turns data into a cultural event. But as developers, waiting 12 months to see our listening habits feels like an eternity.
Why can't we see our data **now?
Welcome to Project Spotiviz. In this three-part series, we aren't just going to fetch a JSON file. We are going to engineer a production-ready, full-stack application that visualizes your music taste in real-time.
What we are building today:
We are ignoring the charts for a moment. Today, we focus on the gatekeeper: Authentication. π
The Goal: By the end of this article, you will have a secure backend that can handshake with Spotify, exchange secret codes for access tokens, and store them in secure, HTTP-only cookies that client-side scripts can't touch.
ποΈ The Architecture
Before we write code, we must understand the flow. Using a third-party API like Spotify isn't as simple as fetch('https://api.spotify.com'). We are dealing with private user data.
We are using the Authorization Code Flow. This is robust and allows us to get a "Refresh Token," meaning our app can stay logged in forever without the user needing to re-approve it every hour.
http://googleusercontent.com/image_generation_content/1
π οΈ The Stack
- Framework: Next.js 14/15 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- State Management: Server-Side Cookies
Phase 1: The Spotify Developer Dashboard
We need to register our application with Spotify to get our credentials.
- Log in to the Spotify Developer Dashboard.
- Click Create App.
- Give it a name (e.g.,
Spotiviz Local). - π¨ Crucial Step: You will see a field for Redirect URIs. This is a whitelist of URLs that Spotify is allowed to return data to. If you don't set this exactly right, the API will block you.
http://googleusercontent.com/image_generation_content/2
Input this exactly:
http://localhost:3000/api/callback
Phase 2: Project Setup & Secrets π€«
Open your terminal. Letβs scaffold a robust Next.js project.
npx create-next-app@latest spotiviz
# Select Yes for TypeScript, Tailwind, ESLint, App Router
Managing Secrets
We need to store our credentials securely. Create a file named .env.local in the root of your project.
http://googleusercontent.com/image_generation_content/4
# .env.local
SPOTIFY_CLIENT_ID=your_client_id_paste_here
SPOTIFY_CLIENT_SECRET=your_client_secret_paste_here
SPOTIFY_REDIRECT_URI=http://localhost:3000/api/callback
Phase 3: The Authorization URL π
We need a button that kicks off the process. We need to construct a specific URL that tells Spotify exactly what permissions (Scopes) we want.
Create a utility library: lib/spotify.ts
const scopes = [
"user-read-recently-played",
"user-top-read",
"user-read-currently-playing",
"user-library-read"
].join(" ");
const params = {
scope: scopes,
response_type: "code",
redirect_uri: process.env.SPOTIFY_REDIRECT_URI!,
client_id: process.env.SPOTIFY_CLIENT_ID!,
};
const queryParamString = new URLSearchParams(params).toString();
export const LOGIN_URL = `https://accounts.spotify.com/authorize?${queryParamString}`;
Pro Tip: If you forget to ask for a specific scope here (like
user-top-read), the API will return a403 Forbiddenerror later when you try to fetch that data.
Phase 4: The "Handshake" (API Route) π€
This is the most critical part of the application.
Spotify redirects the user to http://localhost:3000/api/callback?code=AQDa.... That code is NOT the access token. It is a temporary authorization code.
We must exchange this code Server-Side using a Next.js Route Handler.
File: app/api/callback/route.ts
import { NextResponse } from "next/server";
import { cookies } from "next/headers";
export async function GET(request: Request) {
// 1. Parse the URL to get the "code" parameter
const { searchParams } = new URL(request.url);
const code = searchParams.get("code");
if (!code) {
return NextResponse.json({ error: "No code provided" }, { status: 400 });
}
// 2. Prepare the request to exchange code for a token
const authOptions = {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Authorization:
"Basic " +
Buffer.from(
process.env.SPOTIFY_CLIENT_ID + ":" + process.env.SPOTIFY_CLIENT_SECRET
).toString("base64"),
},
body: new URLSearchParams({
code: code,
redirect_uri: process.env.SPOTIFY_REDIRECT_URI!,
grant_type: "authorization_code",
}).toString(),
};
try {
const response = await fetch("[https://accounts.spotify.com/api/token](https://accounts.spotify.com/api/token)", authOptions);
const data = await response.json();
// 3. Securely store the tokens in Cookies πͺ
const cookieStore = cookies();
cookieStore.set("spotify_access_token", data.access_token, {
httpOnly: true, // Prevents JavaScript access (XSS protection)
secure: process.env.NODE_ENV === "production",
maxAge: 3600,
path: "/",
});
return NextResponse.redirect(new URL("/dashboard", request.url));
} catch (error) {
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}
π Deep Dive: The Cookie Strategy

Why did we use httpOnly: true?
If we stored the token in localStorage, a malicious chrome extension could steal the user's session. With HttpOnly cookies, the browser stores the cookie and attaches it to requests, but JavaScript cannot read it.
http://googleusercontent.com/image_generation_content/3
π Testing The Flow
- Run
npm run dev. - Click your login button.
- Accept the permissions on Spotify's side.
- Open your browser Developer Tools > Application > Cookies.
You should see your secure token sitting there, ready for Part 2.
What's Next?
In Part 2, we will:
- Create the
/dashboardpage. - Handle Token Refresh (keeping the user logged in).
- Transform raw JSON into beautiful charts.
If you found this helpful, drop a comment or a reaction! I'm building this live, so follow along for the next update.
Some really cool YouTube videos
Programming with Mosh. * Video: How to build a REST API with Node js & Express
Why it's great: A comprehensive 1-hour walkthrough on building a REST API from scratch.Fireship Video: RESTful APIs in 100 Seconds // Build an API from Scratch with Node.js Express Why it's great: A fast-paced, high-level overview combined with a practical example.
Traversy Media Video: Learn The MERN Stack - Express & MongoDB Rest API
Why it's great: A full crash course on building a backend API using the popular MERN stack (MongoDB, Express, React, Node).Hussein Nasser Video: gRPC Crash Course - Modes, Examples, Pros & Cons and more
Why it's great: An in-depth engineering look at gRPC, including its pros and cons compared to REST.




Top comments (0)