GithubHelp home page GithubHelp logo

Comments (5)

dieser-niko avatar dieser-niko commented on July 22, 2024 2

My name is Niko actually, but that's all right.

I don't think that the relevant part is included in your snippet, so that's why I straight up built a little example with FastAPI. You said that you're using it as a Backend, so the auth url will be returned as a simple JSON and not as a 307 Temporary Redirect or similar. Check it out: https://github.com/dieser-niko/spotipy-fastapi-oauth

from spotipy.

dieser-niko avatar dieser-niko commented on July 22, 2024 1

It looks like you're on the right track.

The CORS has nothing to do with Spotify and has to be handled by FastAPI instead. You can read more about this here: https://fastapi.tiangolo.com/tutorial/cors/

Then the authentication process. I'd like you to take a look at this app.py example which shows how to get the authorise URL and how a callback from Spotify can be handled. This is a pretty good example, even though it is implemented in Flask. But there's not much difference to FastAPI in this case.

Admittedly, it's a bit tight, because the login process and the callback are implemented in the same function (and therefore the same endpoint).

But it's still possible to understand it. I'll explain it to you.
The function is divided into four parts.

First, the cache_handler and auth_manager are created. They are not passed to spotipy.Spotify yet, and this is important, mainly because of the auth manager, as we don't want to trigger the internal authentication process.

cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private',
                                           cache_handler=cache_handler,
                                           show_dialog=True)

As for the FlaskSessionCacheHandler, I'm not sure if there is something similar for FastAPI. I've seen that you've created your own FastAPISessionCacheHandler, and honestly, it's probably fine to start with. You just have to remember that the user can easily extract the token. They shouldn't be able to do much damage as the token is tied to their account anyway.

Then, in the second part, it checks if the incoming request is from a callback function by checking if "code" is one of the arguments used. The value of this argument is then checked for authenticity. If all is well, the user is logged in and the page is refreshed by redirecting to the same page.

if request.args.get("code"):
    # Step 2. Being redirected from Spotify auth page
    auth_manager.get_access_token(request.args.get("code"))
    return redirect('/')

The third part is to check if the user isn't logged in. If that's the case, then an authorize url is generated and returned to the user as a link. Yes, I know the order of the parts is a bit confusing, but bear with me. There are also comments here and in part 2 to indicate that this step is the first to be run.

if not auth_manager.validate_token(cache_handler.get_cached_token()):
    # Step 1. Display sign in link when no token
    auth_url = auth_manager.get_authorize_url()
    return f'<h2><a href="{auth_url}">Sign in</a></h2>'

And then the last part, where we finally get our spotipy.Spotify object by passing our auth_manager to it. Since we should already be logged in when we reach this part, there should be no prompt asking us to enter a link.

# Step 3. Signed in, display data
spotify = spotipy.Spotify(auth_manager=auth_manager)
return f'<h2>Hi {spotify.me()["display_name"]}, ' \
       f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \
       f'<a href="/playlists">my playlists</a> | ' \
       f'<a href="/currently_playing">currently playing</a> | ' \
       f'<a href="/current_user">me</a>'

I'd recommend running this code on your machine, but be sure to read the comment at the top of the file. It contains some useful information.

I hope I was able to help you.

from spotipy.

wassay13 avatar wassay13 commented on July 22, 2024

Hi Dieser, I tried the the exact same approach you suggest but its not working, heres why:
in get_access_token we have

payload = {
            "redirect_uri": self.redirect_uri,
            "code": code, or self.get_auth_response(),
            "grant_type": "authorization_code",
        }

So when user hit '/' endpoint to my backend (which is running on different server from frontend) for very first time, this function gets called: self.get_auth_response() and the nature of this function is to open new window in computer (server) orr interactive terminal by following the flow it calls: _get_auth_response_interactive in which it actually execute the logic.

    def get_auth_response(self, open_browser=None):
        logger.info('User authentication requires interaction with your '
                    'web browser. Once you enter your credentials and '
                    'give authorization, you will be redirected to '
                    'a url.  Paste that url you were directed to to '
                    'complete the authorization.')

        redirect_info = urlparse(self.redirect_uri)
        redirect_host, redirect_port = get_host_port(redirect_info.netloc)

        if open_browser is None:
            open_browser = self.open_browser

        if (
                open_browser
                and redirect_host in ("127.0.0.1", "localhost")
                and redirect_info.scheme == "http"
        ):
            # Only start a local http server if a port is specified
            if redirect_port:
                return self._get_auth_response_local_server(redirect_port)
            else:
                logger.warning('Using `%s` as redirect URI without a port. '
                               'Specify a port (e.g. `%s:8080`) to allow '
                               'automatic retrieval of authentication code '
                               'instead of having to copy and paste '
                               'the URL your browser is redirected to.',
                               redirect_host, redirect_host)

        return self._get_auth_response_interactive(open_browser=open_browser)

    def _get_auth_response_interactive(self, open_browser=False):
        if open_browser:
            self._open_auth_url()
            prompt = "Enter the URL you were redirected to: "
        else:
            url = self.get_authorize_url()
            prompt = (
                "Go to the following URL: {}\n"
                "Enter the URL you were redirected to: ".format(url)
            )
        response = self._get_user_input(prompt)
        state, code = SpotifyOAuth.parse_auth_response_url(response)
        if self.state is not None and self.state != state:
            raise SpotifyStateError(self.state, state)
        return code


___________________________________________________________________________________

TERMINAL:
(venv) say@ubuntu-xyz:~/app/src$ uvicorn --host 0.0.0.0 main:app

INFO:     137.59.220.8:12607 - "GET /spotify/ HTTP/1.1" 200 OK

INFO:     137.59.220.8:12614 - "GET /spotify/callback?code=AQBoiQiqufrNiKvstckYhncSoyA4DHA HTTP/1.1" 307 Temporary Redirect

Enter the URL you were redirected to: 

from spotipy.

wassay13 avatar wassay13 commented on July 22, 2024

Hey hey hey, ty Niko, it works. Although I've tried it manually which also working perfectly fine but I'll update my code with this approach so I don't fall under unexpected error in future.

from spotipy.

dieser-niko avatar dieser-niko commented on July 22, 2024

Glad to hear that. If you want to, you can change to an authorization header instead of cookies. Probably the only thing I regret about my code :D

from spotipy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.