Jamming - my search button is not working - invalid redirect URI

Hi everyone! My search button is not working! I am at step 95 of the Jamming project and realised that I did not include an “onClick” attribute to the button but then when I click on search it gives an error “INVALID_CLIENT: Invalid redirect URI”

What should I do?

Thanks in advance !

P.S. anyone else noticed that in the video the instructor did not put an onClick attribute to the button and yet it worked? How is that possible?

  1. Can you copy in some of your code so we can see?
  2. Did you make sure to put the redirectUri in to the Spotify Dashboard?
  3. Did you ensure to put the redirectUri in to the code? (A user recently had the same problem and hadn’t done this).

Hi there!! Thank you so much for replying! After reading your comment I check the name of my redictUri on Spotify and realised that I had a type error in the name :expressionless: also I had an type error in the window.setTimeout method! That’s what I get for not copy pasting code…!!Now everything is working fine! I will try to deploy it now…hopefully it will work!

1 Like

Good to hear you found out. Some time you just need to comb through your code to find these errors. It can often be an infuriating experience!

Yes I know! Now I have another problem! I did the surge step and even though I changed (by copy pasting) the redirectUri both in the spotify dashboard and my Spotify.js there is an error again popping up for invalid redirectUri. I did a ‘surge teardown domain_name’ to take it down as it was not working. Then changed it back to my localhost URI and still not working when I click on the search button

1 Like

If you copy your code I can look.

const cliendId = ‘72ea1543cef74b7f97ceef47d6bfdc25’;

const redirectUri = ‘http://localhost3000/’;

let accessToken;

const Spotify = {

getAccessToken() {  

    if(accessToken) {

        return accessToken;

    }

    const accessTokenMatch = window.location.href.match(/access_token=([^&]*)/);

    const expiresInMatch = window.location.href.match(/expires_in=([^&]*)/);

    if (accessTokenMatch && expiresInMatch) {

        accessToken = accessTokenMatch[1];

        const expiresIn = Number(expiresInMatch[1]);

        window.setTimeout(() => accessToken = '', expiresIn * 10000);

        window.history.pushState('Access Token', null, '/');

        return accessToken;

    } else {

        const accessUrl = `https://accounts.spotify.com/authorize?client_id=${cliendId}&response_type=token&scope=playlist-modify-public&redirect_uri=${redirectUri}`;

        window.location = accessUrl;

    }

}, 

search(term) {

    const accessToken = Spotify.getAccessToken();

    return fetch(`https://api.spotify.com/v1/search?type=track&q=${term}`, {

        headers: {

        Authorization: `Bearer ${accessToken}`

    }

    }).then(response => {

    return response.json();

    }).then(jsonResponse => {

    if(!jsonResponse.tracks) {

        return  [];

    }

    return jsonResponse.tracks.items.map(track => ({

        id: track.id,

        name: track.name,

        artist: track.artists[0].name,

        album: track.album.name,

        uri: track.uri

        }));

    });

},

savePlayList(name, trackUris) {

    if(!name || !trackUris.length) {

        return;

    }

    const accessToken = Spotify.getAccessToken();

    const headers = {Authorization: `Bearer ${accessToken}`};

    let userId;

    return fetch('https://api.spotify.com/v1/me', { headers: headers }

    ).then(response => response.json()

    ).then(jsonResponse => {

        userId = jsonResponse.id;

        return fetch(`https://api.spotify.com/v1/users/${userId}/playlists`, 

        {

            headers: headers,

            method: 'POST',

            BODY: JSON.stringify({name: name})

        }).then(response => response.json()

        ).then(jsonResponse => {

            const playlistId = jsonResponse.id;

            return fetch(`https://api.spotify.com/v1/users/${userId}/playlists/${playlistId}/tracks`, 

            {

                headers: headers,

                method: 'POST', 

                body: JSON.stringify({ uris: trackUris})

            })

        })

    })

}

}

export default Spotify;

This is the app.js
import React from ‘react’;

import ‘./App.css’;

import SearchBar from ‘…/SearchBar/SearchBar’;

import SearchResults from ‘…/SearchResults/SearchResults’;

import Playlist from ‘…/Playlist/Playlist’;

import Spotify from ‘…/…/util/Spotify’;

class App extends React.Component {

constructor(props) {

super(props);

this.state = {

  searchResults: [],

  playlistName: 'My Playlist',

  playlistTracks: []

};

this.addTrack = this.addTrack.bind(this);

this.removeTrack = this.removeTrack.bind(this);

this.updatePlaylistName = this.updatePlaylistName.bind(this);

this.savePlaylist = this.savePlaylist.bind(this);

this.search = this.search.bind(this);

}

addTrack(track) {

let tracks = this.state.playlistTracks;

if(tracks.find(savedTrack => savedTrack.id === track.id)) {

  return;

}

tracks.push(track);

this.setState({playlistTracks: tracks});

}

removeTrack(track) {

let tracks = this.state.playlistTracks;

tracks = tracks.filter(currentTrack => currentTrack.id !== track.id);

this.setState({ playlistTracks: tracks });

}

updatePlaylistName(name){

this.setState({playlistName: name});

}

savePlaylist() {

const trackUris = this.state.playlistTracks.map(track => track.uri);

Spotify.savePlayList(this.state.playlistName, trackUris).then(() => {

  this.setState({

    playlistName: 'New Playlist',

    playlistTracks: []

  })

})

}

search(term) {

Spotify.search(term).then(searchResults => {

  this.setState({searchResults: searchResults})

})

}

render() {

return (

  <div>

   <h1>Ja<span className="highlight">mmm</span>ing</h1>

    <div className="App">

      <SearchBar onSearch={this.search} /> 

     <div className="App-playlist">

        <SearchResults searchResults={this.state.searchResults} onAdd={this.addTrack} />

        <Playlist playlistName={this.state.playlistName} 

        playlistTracks={this.state.playlistTracks} onRemove={this.removeTrack}

        onNameChange={this.updatePlaylistName} onSave={this.savePlaylist} /> 

      </div>

    </div>

  </div>

)

}

}

export default App;

Ok I don’t think the problem is your code.
When you did the surge teardown, did you change the spotify redircturi back to the localhost for when you tested?

Also, when you submitted the build version originally to surge did you have the surge address as the redirect BEFORE creating the surge site? If you know what I mean?

Basically, before you do the npm run build the redirectUri in your code needs to already be the surge domain name that you are choosing, because when you submit the build version to surge it uses that code and won’t pick up any changes you make after you’ve run surge in the build file .

So the process should be -

  1. Think of a surge domain name
  2. change the redirectUri
  3. run npm run build => cd build
    4.surge

Ok so I think I did not do that and that’s why it is messed up! How do I correct that?

You correct it by re-doing the steps…

is it possible to update the surge site without taking it down and redeploying?