0
votes

I'm trying to get an application to work with the Microsoft Identity platform.

Sending an OAuth request via Postman appears to work, but when I try the authorizaton_code grant type myself, despite getting back an access token, the API that I'm trying to access always gives me an unauthorized error.

I'm sending a POST request to:

https://login.windows.net/<tenant_id>/oauth2/authorize?resource=<resource_uri>

With body data:

grant_type=authorization_code&
client_id=<client_id>&
redirect_uri=<redirect_uri>&
response_type=code

This gives me a redirect to my URI with the code in the querystring

I then request an access token with the code by sending a POST to:

https://login.windows.net/<tenant_id>/oauth2/token?resource=<resource_uri>

With the following content:

grant_type=authorization_code&
client_id=<client_id>&
redirect_uri=<redirect_uri>&
code=<the_code_from_the_redirect>&
client_secret=<client_secret>

This gives me back an access token:

{
    "token_type": "Bearer",
    "expires_in": "3599",
    "ext_expires_in": "3599",
    "expires_on": "1557783183",
    "not_before": "1557779283",
    "resource": "00000002-0000-0000-c000-000000000000",
    "access_token": "<access_token_here>",
    "refresh_token": "<refresh_token>",
    "id_token": "<id_token>"
}

But this token doesn't work when calling the resource:

{
    "error": {
        "code": "Unauthorized",
        "message": "The credentials provided are incorrect"
    }
}

Doing the same using the Get New Access Token functionality in Postman seems to create the same post request in the Postman console (albeit with a different code, but it has to get a new code because I've already redeemed the other one and it knows nothing about it right?) but the access token that it returns works:

{
    "error": {
        "code": "NoLicense",
        "message": "User has no license"
    }
}

(Ignore the fact that it's an error - the user has no licence for the application I'm trying to query but that's ok)

Am I doing something fundamentally wrong? From what I can see, I'm following the OAuth flow correctly.

1

1 Answers

1
votes

Figured this out - it's because I was passing the resource as part of the querystring and not part of the form.

When the identity platform generates the redirect/callback it only appears to include either the querystring elements when doing a GET or the form elements when doing a POST.

You can see that in the below:

<html>
    <head>
        <title>Continue</title>
    </head>
    <body>
        <form method="POST" name="hiddenform" action="https://login.microsoftonline.com/<tenant_id>/oauth2/authorize">
            <input type="hidden" name="grant_type" value="authorization_code" />
            <input type="hidden" name="client_id" value="<client_id>" />
            <input type="hidden" name="redirect_uri" value="https://businesscentral.dynamics.com" />
            <input type="hidden" name="response_type" value="code" />
            <input type="hidden" name="scope" value="" />
            <noscript>
                <p>Script is disabled. Click Submit to continue</p>
                <input type="submit" value="Submit" />
            </noscript>
        </form>
        <script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
    </body>
</html>

After adding resource to the form data instead of the URL I got a slightly different redirect:

<html>
    <head>
        <title>Continue</title>
    </head>
    <body>
        <form method="POST" name="hiddenform" action="https://login.microsoftonline.com/<tenant_id>/oauth2/authorize">
            <input type="hidden" name="grant_type" value="authorization_code" />
            <input type="hidden" name="client_id" value="<client_id>" />
            <input type="hidden" name="redirect_uri" value="https://businesscentral.dynamics.com" />
            <input type="hidden" name="response_type" value="code" />
            <input type="hidden" name="scope" value="" />
            <input type="hidden" name="resource" value="<resource_id>" />
            <noscript>
                <p>Script is disabled. Click Submit to continue</p>
                <input type="submit" value="Submit" />
            </noscript>
        </form>
        <script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
    </body>
</html>

Which generated me the correct access token!