Last active
March 28, 2019 10:08
-
-
Save bih/1be8b4634ccbcc9fb719e53a57dabc68 to your computer and use it in GitHub Desktop.
Spotify Authentication with React Hooks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { ReactNode } from 'react' | |
import { useSpotifyAccessTokenFromAuthCode, useSpotifyAccessTokenFromRefreshToken } from './hooks' | |
// Store them as environment variables! | |
// | |
const clientId = process.env.SPOTIFY_CLIENT_ID | |
const clientSecret = process.env.SPOTIFY_CLIENT_SECRET | |
const redirectUri = process.env.SPOTIFY_REDIRECT_URI | |
const clientPayload = { clientId, clientSecret, redirectUri } | |
interface AppProps { | |
userSession: boolean | |
refreshToken: string | null, | |
authorizationCode: string | null | |
} | |
export default App(props: AppProps) : ReactNode { | |
if (props.userSession) { | |
// refreshToken will be stored in your database somewhere | |
const accessToken = useSpotifyAccessTokenFromAuthCode({ | |
...clientPayload, | |
refreshToken: props.refreshToken | |
}) | |
} else { | |
// authorizationCode will be passed by Spotify as the "code" parameter | |
const accessToken = useSpotifyAccessTokenFromRefreshToken({ | |
...clientPayload, | |
authorizationCode: props.authorizationCode | |
}) | |
} | |
if (!accessToken) { | |
return <h1>Obtaining your accessToken</h1> | |
} | |
return <h1>Your Access Token: {accessToken}</h1> | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** @format */ | |
import {useState, useEffect} from 'react' | |
if (typeof window !== 'undefined') { | |
throw new Error( | |
[ | |
'This should only be ran in Node.js, and not the browser in any case.', | |
'Why? It will expose your secret credentials which will result in your Spotify client credentials being revoked.', | |
'See article for more information: [insert]', | |
].join('\n'), | |
) | |
} | |
if (typeof fetch === 'undefined') { | |
throw new Error( | |
[ | |
'In order to use this, you will need to use the `node-fetch` package.', | |
'Run the command below to fix this issue.', | |
' $ yarn add node-fetch', | |
].join('\n'), | |
) | |
} | |
interface Constructor { | |
clientId: string | |
clientSecret: string | |
redirectUri: string | |
} | |
interface Request { | |
grant_type: 'authorization_code' | 'refresh_token' | |
client_id: string | |
client_secret: string | |
} | |
interface Response { | |
access_token: string | |
token_type: 'Bearer' | |
scope: string | |
expires_in: number | |
} | |
export interface SpotifyAuthCodeConstructor extends Constructor { | |
authorizationCode: string | null | |
} | |
export interface SpotifyAuthCodeRequest extends Request { | |
redirect_uri: string | |
code: string | |
} | |
export interface SpotifyAuthCodeResponse extends Response {} | |
export interface SpotifyRefreshTokenConstructor extends Constructor { | |
refreshToken: string | null | |
} | |
export interface SpotifyRefreshTokenRequest extends Request { | |
refresh_token: string | |
} | |
export interface SpotifyRefreshTokenResponse extends Response { | |
refresh_token: string | |
} | |
export function useSpotifyAccessTokenFromAuthCode({ | |
authorizationCode, | |
...client | |
}: SpotifyAuthCodeConstructor): string | null { | |
if (!client.clientId || !client.clientSecret || !client.redirectUri || !authorizationCode) { | |
return null; | |
} | |
const [accessToken, setAccessToken] = useState(null) | |
useEffect(() => { | |
const abortController = new AbortController() | |
const body: SpotifyAuthCodeRequest = { | |
client_id: client.clientId, | |
client_secret: client.clientSecret, | |
grant_type: 'authorization_code', | |
redirect_uri: client.redirectUri, | |
code: authorizationCode, | |
} | |
fetch('https://accounts.spotify.com/api/token', { | |
method: 'POST', | |
body: JSON.stringify(body), | |
signal: abortController.signal, | |
}) | |
.then(response => response.json()) | |
.then((response: SpotifyAuthCodeResponse) => setAccessToken(response.access_token)) | |
return function cancel() { | |
abortController.abort() | |
} | |
}, [{authorizationCode, ...client}]) | |
return accessToken | |
} | |
export function useSpotifyAccessTokenFromRefreshToken({ | |
refreshToken, | |
...client | |
}: SpotifyRefreshTokenConstructor): string | null { | |
if (!client.clientId || !client.clientSecret || !client.redirectUri || !refreshToken) { | |
return null; | |
} | |
const [accessToken, setAccessToken] = useState(null) | |
useEffect(() => { | |
const abortController = new AbortController() | |
const body: SpotifyRefreshTokenRequest = { | |
client_id: client.clientId, | |
client_secret: client.clientSecret, | |
grant_type: 'refresh_token', | |
refresh_token: refreshToken, | |
} | |
fetch('https://accounts.spotify.com/api/token', { | |
method: 'POST', | |
body: JSON.stringify(body), | |
signal: abortController.signal, | |
}) | |
.then(response => response.json()) | |
.then((response: SpotifyRefreshTokenResponse) => setAccessToken(response.access_token)) | |
return function cancel() { | |
abortController.abort() | |
} | |
}, [{authorizationCode, ...client}]) | |
return accessToken | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment