Search code examples
pythondjangooauthspotify

The Spotify API callback url has '#' in it instead of '?' how to access parameters in python django


I am using the Implicit grant authorization (1 of 3) types of authorization provided by Spotify.

The callback url looks something like this
http://localhost:8000/callback/#access_token=BQDRRPQ1Nulwcxx...mFNtnTsVUNlkCg&token_type=Bearer&expires_in=3600&state=NtiLgMVtLPx926Ay

If it was
http://localhost:8000/callback/**?**access_token

Then I am able to obtain the query parameters using request.GET in my view, but since it has #, request.GET returns empty dictionary.

I also tried request.build_absolute_uri(), but it returns just http://localhost:8000/callback/

Here is how my view looks

def callback(request, format=None):
    print(request.GET)
    if "access_token" in request.GET:
        print(request.GET["access_token"])

    return HttpResponse("Callback")

I was expecting request.GET to have the access_token, expires in and the parameters that are in the URI, but I'm getting empty dict.


Solution

  • In the Implicit grant authorization flow used by Spotify, the access token and other parameters are typically included in the fragment identifier (after the '#') of the callback URL. However, the fragment identifier is not sent to the server by the browser, so you won't be able to retrieve those parameters using request.GET in your Django view.

    Instead, you can access the fragment identifier and its parameters using JavaScript on the client-side. Here's an example of how you can retrieve the access token using JavaScript and then send it to your server:

    const fragmentString = window.location.hash.substring(1); // Get the fragment identifier without the '#'
    const params = new URLSearchParams(fragmentString); // Parse the parameters
    const accessToken = params.get('access_token'); // Retrieve the access_token parameter
    
    // Send the access token to your server using an AJAX request
    const url = 'http://your-server-endpoint';
    const data = { access_token: accessToken };
    
    fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    })
      .then(response => {
        // Handle the server's response
      })
      .catch(error => {
        // Handle errors
      });
    

    On your server-side, you can define a separate endpoint to handle the access token sent by the JavaScript code:

    # Django view to handle the access token
    from django.http import JsonResponse
    
    def handle_token(request):
        access_token = request.POST.get('access_token')
        # Process the access_token as needed
        return JsonResponse({'message': 'Access token received'})
    
    

    Make sure to set up the appropriate URL routing in your Django application to handle the callback and the token handling endpoints.

    By using JavaScript to retrieve the access token from the fragment identifier and sending it to your server, you can work around the limitation of the fragment identifier not being included in the server's request parameters.