Browser (PKCE)
@spotify-effect/browser provides OAuth PKCE flow support for browser-based applications. PKCE eliminates the need for a client secret, making it safe for frontend-only applications.
Installation
sh bun add @spotify-effect/browser @spotify-effect/core effect
sh npm install @spotify-effect/browser @spotify-effect/core effect
Setup
Create a SpotifyBrowser instance with the required options:
import { SpotifyBrowser } from "@spotify-effect/browser";import * as Layer from "effect/Layer";
const spotify = SpotifyBrowser.layer({ clientId: "your-client-id", redirectUri: "https://yourapp.com/callback", session: { sessionStorage: window.sessionStorage, localStorage: window.localStorage, history: window.history, },});
export const SpotifyLayer = spotify;OAuth Flow
-
Start the login flow
Generate the authorization URL with PKCE challenge:
import { Effect, Layer } from "effect";import { SpotifyBrowser } from "@spotify-effect/browser";const program = Effect.gen(function* () {const spotify = yield* SpotifyBrowser;// Generate URL and redirectconst url = yield* spotify.auth.startPkceLogin({scopes: ["user-read-private", "user-library-read", "playlist-read-private", "streaming"],});window.location.href = url;});Effect.runPromise(program.pipe(Effect.provide(SpotifyLayer))); -
Handle the callback
On your callback page, exchange the authorization code for tokens:
import { Effect } from "effect";import { SpotifyBrowser, readAuthorizationCallback } from "@spotify-effect/browser";const callback = readAuthorizationCallback(new URL(window.location.href));if (callback) {const program = Effect.gen(function* () {const spotify = yield* SpotifyBrowser;const tokens = yield* spotify.auth.exchangeCode(callback.code);console.log("Authenticated!", tokens.accessToken);// Tokens are automatically stored in session/localStorage});Effect.runPromise(program.pipe(Effect.provide(SpotifyLayer)));} -
Access the API
Use any Spotify service after authentication:
const program = Effect.gen(function* () {const spotify = yield* SpotifyBrowser;const user = yield* spotify.users.getCurrentUserProfile();console.log(`Hello, ${user.display_name}!`);});
Session Management
Check authentication status
const tokens = spotify.auth.getTokens();
if (tokens) { // User is authenticated const expiresAt = new Date(tokens.accessTokenExpiresAt); console.log(`Token expires at: ${expiresAt}`);}Automatic token refresh
Tokens are automatically refreshed when the browser client has both a refreshToken and an accessTokenExpiresAt value. That applies to tokens returned from exchangeCode, tokens restored from storage, and tokens provided through setTokens. Call refreshToken to proactively refresh:
const program = Effect.gen(function* () { const spotify = yield* SpotifyBrowser; const tokens = yield* spotify.auth.refreshToken(currentRefreshToken); console.log("Tokens refreshed!");});Logout
spotify.auth.logout();// Clears tokens from browser storage and the live in-memory sessionAvailable Services
The browser package provides all the same services as @spotify-effect/core:
albums— Get albums, tracks, and album metadataartists— Get artists, albums, and related artistsbrowse— Featured playlists, categories, new releasesfollow— Follow/unfollow artists and userslibrary— Saved albums and tracksmarkets— Available marketspersonalization— Top artists and tracksplayer— Playback control (requiresstreamingscope)playlists— Manage playlistssearch— Search the catalogtracks— Track audio features and analysisusers— User profiles
Example: Build a simple player
import { Effect } from "effect";import { SpotifyBrowser } from "@spotify-effect/browser";
const program = Effect.gen(function* () { const spotify = yield* SpotifyBrowser;
// Get user's top tracks const topTracks = yield* spotify.personalization.getMyTopTracks({ limit: 10, });
// Start playback const uris = topTracks.items.map((track) => track.uri); yield* spotify.player.play({ uris });});
Effect.runPromise(program.pipe(Effect.provide(SpotifyLayer)));Next steps
- Error Handling — handle browser-specific errors
- Authentication — understand OAuth flows
- Pagination — paginate through results