Authorize with Spotify using Nginx reverse proxy for client

I have a docker app running three services:

  • client –> react frontend
  • web — > flask backend
  • nginx ->- a reverse proxy for both

This is the (simplified) project structure:

docker-compose-dev.yml
services/
        client/
              src/
                 Spotify.js
         nginx/
              dev.conf
         web/

Here is where I defined exposed ports at built time:

docker-compose-dev.yml

  web:
    build:
      context: ./services/web
      dockerfile: Dockerfile-dev
    volumes:
      - './services/web:/usr/src/app'
    ports:
      - 5001:5000 <----------------
    environment:
      - FLASK_ENV=development
      - APP_SETTINGS=project.config.DevelopmentConfig
    depends_on:  
      - web-db

  nginx:
    build:
      context: ./services/nginx
      dockerfile: Dockerfile-dev
    restart: always
    ports:
      - 80:80     <----------------
      - 8888:8888 <----------------
    depends_on:
      - web
      - client

  client:
    build:
      context: ./services/client
      dockerfile: Dockerfile-dev
    volumes:
      - './services/client:/usr/src/app'
      - '/usr/src/app/node_modules'
    ports:
      - 3007:3000   <----------------
    environment:
      - NODE_ENV=development
      - REACT_APP_WEB_SERVICE_URL=${REACT_APP_WEB_SERVICE_URL}
    depends_on:
      - web

I build services like so:

$ export REACT_APP_WEB_SERVICE_URL=http://localhost
$ docker-compose -f docker-compose-dev.yml up -d --build

REDIRECT

Client service, on its turn, needs to authenticate with Spotify, which requires a Redirect URI, whitelisted at https://developer.spotify.com. For mine, I have several options:

enter image description here

This is my nginx file, where I try to organize the right ports:

dev.conf

server {

  listen 80;
  listen 8888;

  location / {        // frontend at localhost:3000
    proxy_pass        http://client:3000;
    proxy_redirect    default;
    proxy_set_header  Upgrade $http_upgrade;
    proxy_set_header  Connection "upgrade";
    proxy_set_header  Host $host;
    proxy_set_header  X-Real-IP $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Host $server_name;
  }

  location /users {   // backend at localhost:5000
    proxy_pass        http://web:5000;
    proxy_redirect    default;
    proxy_set_header  Upgrade $http_upgrade;
    proxy_set_header  Connection "upgrade";
    proxy_set_header  Host $host;
    proxy_set_header  X-Real-IP $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Host $server_name;
  }

  location /auth {    # this authentication is for the app, not spotify
    proxy_pass        http://web:5000;
    proxy_redirect    default;
    proxy_set_header  Upgrade $http_upgrade;
    proxy_set_header  Connection "upgrade";
    proxy_set_header  Host $host;
    proxy_set_header  X-Real-IP $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Host $server_name;
  }
}

Finally, there’s my javascript file in order who to:

  1. Authenticate with Spotify
  2. Redirect my app back to localhost

Spotify.js

import React, { Component } from 'react';
//import axios from 'axios';

import './Spotify.css'

// import SpotifyWebApi from 'spotify-web-api-js';
// const spotifyApi = new SpotifyWebApi();



const stateKey = 'spotify_auth_state';
const client_id = 'd3b2f7a12362468daa393cf457185973'; // Your client id
const redirect_uri = 'http://localhost:3000'; 
const scope =
  'user-read-private user-read-email user-read-playback-state playlist-modify-public playlist-modify-private';

function generateRandomString(length) {
  let text = '';
  const possible =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

  for (let i = 0; i < length; i++) {
    text += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  return text;
}

class SpotifyAuth extends Component {
  getHashParams() {
    const hashParams = {};
    const r = /([^&;=]+)=?([^&;]*)/g;
    const q = window.location.hash.substring(1);
    let e = r.exec(q);
    while (e) {
      hashParams[e[1]] = decodeURIComponent(e[2]);
      e = r.exec(q);
    }
    return hashParams;
  }

  componentDidMount() {
    const params = this.getHashParams();

    const access_token = params.access_token;
    const state = params.state;
    const storedState = localStorage.getItem(stateKey);
    localStorage.setItem('spotify_access_token', access_token);
    localStorage.getItem('spotify_access_token');

    if (access_token && (state == null || state !== storedState)) {
      alert('There was an error during the authentication');
    } else {
      localStorage.removeItem(stateKey);
    }

    // DO STUFF WITH ACCESS TOKEN HERE
  }

  handleRedirect() {
    const state = generateRandomString(16);
    localStorage.setItem(stateKey, state);

    let url = 'https://accounts.spotify.com/authorize';
    url += '?response_type=token';
    url += '&client_id=' + encodeURIComponent(client_id);
    url += '&scope=' + encodeURIComponent(scope);
    url += '&redirect_uri=' + encodeURIComponent(redirect_uri);
    url += '&state=' + encodeURIComponent(state);

    //axios.get(url).then(response => console.log(response));

    window.location = url;
  }

  render() {
    return (
      <div className="button__container">
        <button className="button" onClick={this.handleRedirect}>
          <strong>CONNECT YOUR SPOTIFY ACCOUNT</strong>
        </button>
      </div>
    );
  }
}


export default SpotifyAuth;

and render flow, at:

App.jsx

render() {
  return (
  <div>  
    <Switch>
      <Route exact path='/' render={() => (
        <SpotifyAuth/>
       )} />
    </Switch>
   </div>

After all of this is set and run, I get:

INVALID_CLIENT: Invalid redirect URI 

What am I missing? what is the most reliable way of authenticating with Spotify on a docker project like this one?

Source: StackOverflow