Skip to content

Commit

Permalink
Prompt for re-authentication upon token expiry
Browse files Browse the repository at this point in the history
This way whenever the API rejects the token we automatically ask for the refreshed one and go from there.
  • Loading branch information
TomasHubelbauer committed Jun 3, 2024
1 parent af47b8f commit 40e6811
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 41 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,4 @@ Build a repo which just shows the current time or a random number or something.
- Replaced track ID web search lookup with a Spotify AppleScript command
- Rewrote to use the Spotify API directly instead of via the Heroku app
- Upgraded to latest Electron and started using ESM and TLA
- Implemented a re-authorization flow for obtaining the new token after a 401
55 changes: 14 additions & 41 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,14 @@ import electron from 'electron';
import timers from 'timers/promises';
import fs from 'fs';
import askSpotify from './askSpotify.js';
import promptAuthorization from './promptAuthorization.js';

electron.app.on('ready', async () => {
// Prevent "exited with signal SIGINT" to be printed to the console
// Note that this must be in the `ready` event handler
process.on("SIGINT", () => { });

/** @type {string} */
let authorization;

const path = `token.json`;
try {
await fs.promises.access(path);

console.log('Loading bearer token…');
authorization = JSON.parse(await fs.promises.readFile(path));
console.log('Loaded bearer token');
}
catch (error) {
if (error.code !== 'ENOENT') {
console.log(`Failed to load bearer token: ${error}`);
}

console.log('Obtaining bearer token…');
const window = new electron.BrowserWindow({ width: 800, height: 600 });
window.loadURL('https://open.spotify.com/');

authorization = await new Promise((resolve) => {
electron.session.defaultSession.webRequest.onSendHeaders(
{ urls: ['https://gew4-spclient.spotify.com/*'] },
(details) => {
if (authorization) {
return;
}

if (details.requestHeaders['authorization']) {
resolve(details.requestHeaders['authorization']);
}
}
);
});

window.close();
await fs.promises.writeFile(path, JSON.stringify(authorization, null, 2));
console.log('Obtained bearer token');
}
let authorization = await promptAuthorization();

// Hide the Dock icon for the application
electron.app.dock.hide();
Expand Down Expand Up @@ -167,7 +130,7 @@ electron.app.on('ready', async () => {
}

// Download new lyrics if we don't already have them
if (lyrics?.artist !== artist || lyrics?.song !== song) {
if (authorization && (lyrics?.artist !== artist || lyrics?.song !== song)) {
const path = `lyrics/${artist} - ${song}.json`;
try {
await fs.promises.access(path);
Expand Down Expand Up @@ -206,7 +169,17 @@ electron.app.on('ready', async () => {
console.log(`Downloaded lyrics for ${artist} - ${song} (${id})`);
}
else {
lyrics = { artist, song, error: response.statusText };
lyrics = { artist, song, error: response.status + ' ' + response.statusText };

// Force the user to re-authenticate if the token is invalid
if (response.status === 401) {
// Reset the field while re-authenticating to prevent multiple prompts
authorization = undefined;
authorization = await promptAuthorization(true);

// Reset the lyrics so they are re-tried with the new token
lyrics = undefined;
}
}
}

Expand Down
57 changes: 57 additions & 0 deletions promptAuthorization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import fs from 'fs';
import electron from 'electron';

export default async function promptAuthorization(force = false) {
/** @type {string} */
let authorization;

const path = `token.json`;
if (force) {
try {
await fs.promises.unlink(path);
}
catch (error) {
if (error.code !== 'ENOENT') {
console.log(`Failed to delete bearer token: ${error}`);
}
}
}

try {
await fs.promises.access(path);

console.log('Loading bearer token…');
authorization = JSON.parse(await fs.promises.readFile(path));
console.log('Loaded bearer token');
}
catch (error) {
if (error.code !== 'ENOENT') {
console.log(`Failed to load bearer token: ${error}`);
}

console.log('Obtaining bearer token…');
const window = new electron.BrowserWindow({ width: 1024, height: 800 });
window.loadURL('https://open.spotify.com/');

authorization = await new Promise((resolve) => {
electron.session.defaultSession.webRequest.onSendHeaders(
{ urls: ['https://gew4-spclient.spotify.com/*'] },
(details) => {
if (authorization) {
return;
}

if (details.requestHeaders['authorization']) {
resolve(details.requestHeaders['authorization']);
}
}
);
});

window.close();
await fs.promises.writeFile(path, JSON.stringify(authorization, null, 2));
console.log('Obtained bearer token');
}

return authorization;
}

0 comments on commit 40e6811

Please sign in to comment.