Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/josteinkringlen/remix-auth-spotify
https://github.com/josteinkringlen/remix-auth-spotify
remix remix-auth remix-run spotify
Last synced: 11 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/josteinkringlen/remix-auth-spotify
- Owner: JosteinKringlen
- License: mit
- Created: 2022-01-27T17:06:21.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2024-09-17T07:15:00.000Z (about 2 months ago)
- Last Synced: 2024-09-18T07:02:19.801Z (about 2 months ago)
- Topics: remix, remix-auth, remix-run, spotify
- Language: TypeScript
- Homepage:
- Size: 2.47 MB
- Stars: 11
- Watchers: 2
- Forks: 1
- Open Issues: 12
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Remix Auth - Spotify Strategy
The Spotify strategy is used to authenticate users against a Spotify account. It extends the OAuth2Strategy.
The strategy supports refreshing expired access tokens. The logic for this is ~~stolen from~~ heavily inspired by [remix-auth-supabase](https://github.com/mitchelvanbever/remix-auth-supabase) – thanks [@mitchelvanbever](https://github.com/mitchelvanbever)!
## Supported runtimes
| Runtime | Has Support |
| ---------- | ----------- |
| Node.js | ✅ |
| Cloudflare | ✅ |## How to use
### Create application in Spotify developer dashboard
1. Go to the [Spotify developer dashboard](https://developer.spotify.com/dashboard/applications) and sign in with your account
2. Click `Create an app` and give the application a suitable name and description
3. Click `Edit settings` and add
- `http://localhost:3000` under `Website`
- `http://localhost:3000/auth/spotify/callback` under `Redirect URIs` (remember to hit `Add`)
4. Hit `Save` at the bottom of the modal
5. Grab your client ID and secret from the dashboard overview, and save them as env variablesRemember to update `Website` and `Redirect URIs` if/when deploying your app.
### Install remix-auth and the Spotify strategy
``` bash
npm install remix-auth remix-auth-spotify
# or
yarn add remix-auth remix-auth-spotify
```### Setup env variables, sessionStorage, strategy and authenticator
```bash
# .env
SPOTIFY_CLIENT_ID="your client id"
SPOTIFY_CLIENT_SECRET="your client secret"
SPOTIFY_CALLBACK_URL="your callback url" # e.g. http://localhost:3000/auth/spotify/callback
``````TypeScript
// app/services/session.server.ts
import { createCookieSessionStorage } from '@remix-run/node';export const sessionStorage = createCookieSessionStorage({
cookie: {
name: '_session', // use any name you want here
sameSite: 'lax',
path: '/',
httpOnly: true,
secrets: ['s3cr3t'], // replace this with an actual secret from env variable
secure: process.env.NODE_ENV === 'production', // enable this in prod only
},
});export const { getSession, commitSession, destroySession } = sessionStorage;
``````TypeScript
// app/services/auth.server.ts
import { Authenticator } from 'remix-auth';
import { SpotifyStrategy } from 'remix-auth-spotify';import { sessionStorage } from '~/services/session.server';
if (!process.env.SPOTIFY_CLIENT_ID) {
throw new Error('Missing SPOTIFY_CLIENT_ID env');
}if (!process.env.SPOTIFY_CLIENT_SECRET) {
throw new Error('Missing SPOTIFY_CLIENT_SECRET env');
}if (!process.env.SPOTIFY_CALLBACK_URL) {
throw new Error('Missing SPOTIFY_CALLBACK_URL env');
}// See https://developer.spotify.com/documentation/general/guides/authorization/scopes
const scopes = ['user-read-email'].join(' ');export const spotifyStrategy = new SpotifyStrategy(
{
clientID: process.env.SPOTIFY_CLIENT_ID,
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
callbackURL: process.env.SPOTIFY_CALLBACK_URL,
sessionStorage,
scope: scopes,
},
async ({ accessToken, refreshToken, extraParams, profile }) => ({
accessToken,
refreshToken,
expiresAt: Date.now() + extraParams.expiresIn * 1000,
tokenType: extraParams.tokenType,
user: {
id: profile.id,
email: profile.emails[0].value,
name: profile.displayName,
image: profile.__json.images?.[0]?.url,
},
}),
);export const authenticator = new Authenticator(sessionStorage, {
sessionKey: spotifyStrategy.sessionKey,
sessionErrorKey: spotifyStrategy.sessionErrorKey,
});authenticator.use(spotifyStrategy);
```### Setup authentication routes
```TSX
// app/routes/auth.spotify.tsx
import type { ActionFunctionArgs } from '@remix-run/node';
import { redirect } from '@remix-run/node';import { authenticator } from '~/services/auth.server';
export function loader() {
return redirect('/login');
}export async function action({ request }: ActionFunctionArgs) {
return await authenticator.authenticate('spotify', request);
}
``````TSX
// app/routes/auth.spotify.callback.tsx
import type { LoaderFunctionArgs } from '@remix-run/node';import { authenticator } from '~/services/auth.server';
export function loader({ request }: LoaderFunctionArgs) {
return authenticator.authenticate('spotify', request, {
successRedirect: '/',
failureRedirect: '/login',
});
}
``````TSX
// app/routes/logout.tsx
import type { ActionFunctionArgs } from '@remix-run/node';
import { json, redirect } from '@remix-run/node';import { destroySession, getSession } from '~/services/session.server';
export async function action({ request }: ActionFunctionArgs) {
return redirect('/', {
headers: {
'Set-Cookie': await destroySession(
await getSession(request.headers.get('cookie')),
),
},
});
}export function loader() {
throw json({}, { status: 404 });
}
```### Use the strategy
> `spotifyStrategy.getSession()` works similar to `authenticator.isAuthenticated()`, only it handles refreshing tokens. If you don't need to refresh tokens in your app, feel free to use `authenticator.isAuthenticated()` instead.
```TSX
// app/routes/_index.tsx
import type { LoaderFunctionArgs } from '@remix-run/node';
import { Form, useLoaderData } from '@remix-run/react';import { spotifyStrategy } from '~/services/auth.server';
export async function loader({ request }: LoaderFunctionArgs) {
return spotifyStrategy.getSession(request);
}export default function Index() {
const data = useLoaderData();
const user = data?.user;return (
Welcome to Remix!
Check out the docs to get
started.
{user ? (
You are logged in as: {user?.email}
) : (
You are not logged in yet!
)}
{user ? 'Logout' : 'Log in with Spotify'}
);
}
```