Search code examples
python-3.xoauth-2.0azure-active-directory

How to Redeem an authorization code for an access token


I am in the process of using a microsoft oauth2 workflow which starts by having a user signin to a portal granting an authorization code which is 'redeemed' for an access token and I'm having issues with the redeeming portion.

The script starts by opening a browser to a url that will send that authorization code to a local webserver which takes that code and sends another request to a microsoft endpoint which returns to error message: The request body must contain the following parameter: 'grant_type'.

Quick assumptions: my application is properly registered and configured, the redirect uri is added properly

import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer

import requests


class RequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(bytes("Thanks for logging in!", "utf-8"))
        self.server.code = self.path.split("=")[1]
        self.server.stop = True

        global activationCode
        activationCode = self.server.code

client_id = "client id here"
redirect_uri = "http://localhost:8080"

endpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id={}&response_type=code&redirect_uri={}&response_mode=query&scope={}&state={}".format(
        client_id, # client id
        redirect_uri, # redirect uri
        "XboxLive.signin", # scope
        "12345", # state
    )


global activationCode
activationCode = None
httpServer = HTTPServer(("localhost", 8080), RequestHandler)

webbrowser.open(endpoint)

while not activationCode:
    httpServer.handle_request()

print("Got activation code")

print("Fetching access token")
endpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token?client_id={}&scope={}&code={}&redirect_uri={}&grant_type=authorization_code".format(
        client_id, # client id
        "XboxLive.signin", # scope
        activationCode, # code
        redirect_uri, # redirect uri
    )

res = requests.post(endpoint, headers={
    "Content-Type": "application/x-www-form-urlencoded"
})

print(res.json())


Solution

  • The second request must be a POST, so send parameters like these in the body of the request to the token endpoint:

    endpoint = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
    
    body = {
      "client_id": myclient, 
      "client_secret": mysecret,
      "code": mycode,
      "redirect_uri": myredirecturi,
      "grant_type": "authorization_code"}
    
    res = requests.post(
      endpoint, 
      headers={
        "Content-Type": "application/x-www-form-urlencoded"}
      data=body
    )