import * as admin from 'firebase-admin' ; import { NextApiRequest , NextApiResponse } from 'next' ; import { encrypt } from 'common/utils/encrypt' ; import { initializeAdminApp } from 'services/firebase.server' ; const REDIRECT_URL = process . env . SPOTIFY_URL || 'http://localhost:3000/signin' ; const SpotifyWebApi = require ( 'spotify-web-api-node' ) ; const Spotify = new SpotifyWebApi ( { clientId : process . env . SPOTIFY_CLIENT_ID , clientSecret : process . env . SPOTIFY_CLIENT_SECRET , redirectUri : REDIRECT_URL , } ) ; /**
 * Exchanges a given Spotify auth code passed in the 'code' URL query parameter for a Firebase auth token.
 * The request also needs to specify a 'state' query parameter which will be checked against the 'state' cookie.
 * The Firebase custom auth token is sent back in a JSONP callback function with function name defined by the
 * 'callback' query parameter.
 */ export default ( req , res ) => { try { if ( ! req . cookies . state ) { throw new Error ( 'State cookie not set or expired. Maybe you took too long to authorize. Please try again.' ) ; } else if ( req . cookies . state !== req . query . state ) { throw new Error ( 'State validation failed' ) ; } type FirebaseBody = { body : { access_token : string ; refresh_token : string ; } ; } ; type SpotifyBody = { body : { id : string ; images ? : { url ? : string ; } [ ] ; display_name ? : string ; email : string ; } ; } ; Spotify . authorizationCodeGrant ( req . query . code , ( error , data ) => { if ( error ) { throw error ; } Spotify . setAccessToken ( data . body [ 'access_token' ] ) ; Spotify . getMe ( async ( error , userResults ) => { if ( error ) { throw error ; } const accessToken = data . body [ 'access_token' ] ; const refreshToken = data . body [ 'refresh_token' ] ; const spotifyUserID = userResults . body [ 'id' ] ; const userName = userResults . body ?. [ 'display_name' ] ?? '' ; const profilePic = userResults . body ?. [ 'images' ] ?. [ 0 ] ?. [ 'url' ] ?? `https://eu.ui-avatars.com/api/?name=${ userName . replace ( / /g , '+' ) }` ; const firebaseToken = await createFirebaseAccount ( spotifyUserID , userName , profilePic , accessToken , refreshToken ) ; res . json ( { token : firebaseToken } ) ; } ) ; } ) ; } catch ( err ) { res . status ( 500 ) . json ( { error : err . message } ) ; } return null ; } ; returns { Promise < string > } async function createFirebaseAccount ( spotifyID , displayName , photoURL , accessToken , refreshToken ) { initializeAdminApp ( ) ; const uid = encrypt ( spotifyID ) ; await admin . database ( ) . ref ( `/spotifyAccessToken/${ uid }` ) . update ( { accessToken , refreshToken } ) ; await admin . auth ( ) . updateUser ( uid , { displayName : displayName , photoURL : photoURL , } ) . catch ( ( error ) => { if ( error . code === 'auth/user-not-found' ) { return admin . auth ( ) . createUser ( { uid : uid , displayName : displayName , photoURL : photoURL , } ) ; } throw error ; } ) ; const token = await admin . auth ( ) . createCustomToken ( uid ) ; return token ; }