Skip to content

windsuzu/spotify-clone

Repository files navigation

A Spotify clone project built with TypeScript, React/Redux, Nextjs, TailwindCSS, etc. Users can log into Spotify with NextAuth and get Spotify's permissions and control API through spotify-web-api-node. The general users can see their song list on this site, and Premium level users can control the playback of their songs and volume directly on this site.

❤️ This project is under development mode, so if you would like to try out this demo, please contact me and provide me with an email of your Spotify account. 😀

Installation

  • install Next.js with Typescript
npx create-next-app@latest --ts spotify-clone
// or 
npx create-next-app@latest -e with-typescript spotify-clone
  • install tailwindcss
https://tailwindcss.com/docs/guides/nextjs
  • install @reduxjs/toolkit and react-redux
npm install @reduxjs/toolkit react-redux

Login Spotify (NextAuth.js and Spotify-Web-Api-Node)

We use NextAuth to login to Spotify and Spotify-Web-Api-Node to get the user information.

0 - Dependencies

1 - Setup Spotify-Web-Api-Node

  • Spotify-Web-Api-Node helps us to login Spotify and re-login with refreshtoken
  • LOGIN_URL is the login page the user will be redirected to
  • spotifyApi can refresh user's accesstoken, get user's contents
  • Source code
// lib/spotify.ts

import SpotifyWebApi from "spotify-web-api-node";

export const LOGIN_URL = `https://accounts.spotify.com/authorize?${new URLSearchParams(
    params
).toString()}`;

const spotifyApi = new SpotifyWebApi({
    clientId: process.env.SPOTIFY_CLIENT_ID,
    clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
});

export default spotifyApi;

2 - Setup NextAuth

  • NextAuth contains dynamic route handler and all other global configurations, such as JWT secret key, custom pages, custom callbacks
  • Source code

2-1 API Route

  • providers lets you place authentication platforms such as Github, Spotify, etc.
export default NextAuth({
    providers: [
        SpotifyProvider({
            clientId: process.env.SPOTIFY_CLIENT_ID!,
            clientSecret: process.env.SPOTIFY_CLIENT_SECRET!,
            authorization: LOGIN_URL,
        }),
        // you can add more providers here...
    ],
})

2-2 callbacks jwt

In our example:

  1. When user initial login, a token with addtional info such as User ID, OAuth Access Token is returned
  2. When user accesses with an unexpired token, the token itself is returned
  3. When user's token is expired, we use spotifyApi to refresh user's token
callbacks: {
    async jwt({ token, account, user }) {
        // initial sign in
        if (account && user) {
            return {
                ...token,
                accessToken: account.access_token,
                refreshToken: account.refresh_token,
                userId: account.providerAccountId,
                accessTokenExpires: account.expires_at! * 1000,
            };
        }

        // accessToken still valid
        if (Date.now() < (token as SpotifyJWT).accessTokenExpires * 1000) {
            return token;
        }

        // accessToken expired, refresh it
        return await refreshAccessToken(token as SpotifyJWT);
    },
},

2-3 callbacks session

  • When using JWT for sessions, the JWT payload is provided here for further delivery to the client
  • Documentation
callbacks: {
    ...,
    async session({ session, token }) {
        session.accessToken = (token as SpotifyJWT).accessToken;
        session.refreshToken = (token as SpotifyJWT).refreshToken;
        session.userId = (token as SpotifyJWT).userId;

        return session;
    },
}

3 - Setup Custom Front-End Login Page

  • useProvider in getServerSideProps gets the providers (e.g. Spotify) defined in NextAuth and pass them to the client
  • LoginPage renders login button for each providers (in our case, we only have one provider - Spotify)
  • You need to set Redirect URIs to http://localhost:3000/api/auth/callback/spotify in Spotify for Developer
  • Documentation for signIn()
  • Source Code
const LoginPage = ({ providers }: Props) => {
    ...
    {Object.values(providers).map((provider) => (
        <div key={provider.name}>
            <button
                onClick={() =>
                    signIn(provider.id, { callbackUrl: "/" })
                }>
                Login with {provider.name}
            </button>
        </div>
    ))}
    ...
};

export async function getServerSideProps() {
    const providers = await getProviders();
    return {
        props: {
            providers,
        },
    };
}

4 - Setup Session Provider

  • Before we can access token in client side with useSession(), or in server side with getSession(), we have to setup SessionProvider in the _app
  • Documentation
import { SessionProvider } from "next-auth/react";

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
    return (
        <SessionProvider session={session}>
            <Component {...pageProps} />
        </SessionProvider>
    );
}

5 - Use useSession() to get token data

  • Now we can use useSession() to access the token in the react client
  • Documentation
import { useSession } from "next-auth/react";

const Home = () => {
    const { data: session, status } = useSession();
    ...
}

6 - Setup Nextjs Middleware

export async function middleware(req: any) {
    const secret = process.env.JWT_SECRET!;
    const token = await getToken({ req, secret });
    const { pathname, origin } = req.nextUrl;

    if (token || pathname.includes("/api/auth") || pathname === "/login") {
        return NextResponse.next();
    }

    if (!token) {
        return NextResponse.redirect(origin + "/login");
    }
}

7 - Use getSession before client-side rendering

  • Use getSession() in SSR can pre-fetch authorization from Spotify
  • Source Code
export const getServerSideProps: GetServerSideProps = async (context) => {
    const session = await getSession(context);
    return {
        props: { session },
    };
};

Components

State Management

Redux

useContext

Acknowledgement

About

A Spotify clone project built with TypeScript, Redux, Nextjs, and TailwindCSS. This project can actually connect to Spotify via NextAuth and spotify-web-api-node!

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published