The words Under construction in black text on a yellow background with diagonal black stipes surrounding it
I'm in the process of moving my site. It's still a work in progress. Please excuse the mess and broken links.

Tuneify - Login

TODO: Pull subtitle into page object

Debugging Stuff

I'm moving stuff around right now. All this below is helping me figure out where to put stuff

        -- title

Tuneify - Login



-- html
-- type: showbelow

<div id="spotifyId"></div>
<div id="spotifySpace"></div>

-- script
-- type: show
-- title: JavaScript: Config

const clientId = 'cd3e61bde252419da1e9b1051947a9a4'
const redirectUri = 'http://localhost:3300/pages/2zzhu9pt/'
const verify_token_key = "tuneify_verify_token"
const access_token_key = "tuneify_access_token"
const user_id_key = "tuneify_user_id"
const scopes = [
  'user-read-private', 
  'user-read-email'
]
const scope = scopes.join(" ")


-- script
-- type: show
-- title: JavaScript: Main Script 


const generateRandomString = (length) => {
  const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  const values = crypto.getRandomValues(new Uint8Array(length))
  return values.reduce((acc, x) => acc + possible[x % possible.length], "")
}

const codeVerifier  = generateRandomString(64)

const sha256 = async (plain) => {
  const encoder = new TextEncoder()
  const data = encoder.encode(plain)
  return window.crypto.subtle.digest('SHA-256', data)
}

const base64encode = (input) => {
  return btoa(String.fromCharCode(...new Uint8Array(input)))
    .replace(/=/g, '')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
}

const startLogin = async () => {
  const hashed = await sha256(codeVerifier)
  const codeChallenge = base64encode(hashed)
  const authUrl = new URL("https://accounts.spotify.com/authorize")
  window.localStorage.setItem(verify_token_key, codeVerifier)
  const params =  {
    response_type: 'code',
    client_id: clientId,
    scope,
    code_challenge_method: 'S256',
    code_challenge: codeChallenge,
    redirect_uri: redirectUri,
  }
  authUrl.search = new URLSearchParams(params).toString()
  window.location.href = authUrl.toString()
}

const getToken = async (code) => {
  let codeVerifier = localStorage.getItem(verify_token_key)
  const payload = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: new URLSearchParams({
      client_id: clientId,
      grant_type: 'authorization_code',
      code,
      redirect_uri: redirectUri,
      code_verifier: codeVerifier,
    }),
  }
  const url = new URL("https://accounts.spotify.com/api/token")
  const body = await fetch(url, payload)
  const response = await body.json()
  localStorage.setItem(access_token_key, response.access_token)
  localStorage.removeItem(verify_token_key)
  window.location.href = redirectUri
}

const getData = async (method, endpoint) => {
  /****************************************i**
     NOTE: This is a sample an only set up to 
     work with simple GET requests 
  ********************************************/
  const payload = {
    method: method,
    headers: {
      'Authorization': `Bearer  ${localStorage.getItem(access_token_key)}`
    }
  }
  const body = await fetch(`https://api.spotify.com/v1${endpoint}`, payload)
  const response = await body.json()
  return response
}

const launchApp = async () => {
  while (spotifySpace.children.length > 0) {
    spotifySpace.children[0].remove()
  }
  const logoutButton = document.createElement("button")
  logoutButton.innerText = "log out"
  logoutButton.addEventListener("click", doLogout)
  spotifySpace.appendChild(logoutButton)
  const user_data = await getData('GET', '/me')
  console.log(user_data)
  localStorage.setItem(user_id_key, user_data.id)
  spotifyId.innerHTML = user_data.id
}

const doLogout = () => {
  localStorage.removeItem(access_token_key)
  localStorage.removeItem(user_id_key)
  switchToLogin()
}

document.addEventListener('DOMContentLoaded', () => {
  if (localStorage.getItem(access_token_key)) {
    /* TODO: Check if token has expired */
    /* TODO: And deal with refresh tokens */
    launchApp()
  }
  else {
    const urlParams = new URLSearchParams(window.location.search);
    let code = urlParams.get('code');
    /* TODO: Check for error here */
    if (code) {
      getToken(code)
    } 
    else {
      switchToLogin()
    }
  }
})


const switchToLogin = () => {
  while (spotifySpace.children.length > 0) {
    spotifySpace.children[0].remove()
  }
  const loginButton = document.createElement("button")
  loginButton.innerText = "log in"
  loginButton.addEventListener("click", startLogin)
  spotifySpace.appendChild(loginButton)
  spotifyId.innerHTML = "Not logged in" 
}


-- metadata
-- date: 2023-12-24 05:40:00
-- id: 2zzhu9pt
-- site: aws
-- type: post
-- status: draft