Message for Allen Helton

Hi @allenheltondev I read your Article which is something Iā€™ve wanted for a while - one thing Iā€™m unsure of, is, where to put my client_id and client_secret, it looks like they go in the variable Basic_Auth but as itā€™s multiple values I donā€™t know how to do it - could you show me how it should be done please - it will be really good to get this working - thanks for a great article

Hey @pkfox :wave:

Welcome to the Postman community! :postman:

Might be good to tag @allenheltondev in the message so that he can see the love and the question.

Failing that, you could reach out to him here too:

https://x.com/AllenHeltonDev

https://www.linkedin.com/in/allenheltondev

Thanks Danny but I donā€™t do the social media stuff

I reached out to Allen to make him aware of your message. :trophy:

Thanks @danny-dainton for the ping.

Hey @pkfox, basic auth is a base64 encoded version of your client id and secret. You can create the value by hand by base64 encoding <client id>:<client secret> or you can use a website that does it for you, like this one.

1 Like

Thanks Allen, do I populate the Postman Basic_Auth variable like this client_id:abase64encodedvalue , client_secret:anotherbase64encodedvalue
do i need to separate the values with commas

Thanks @danny-dainton

1 Like

These logs might help

POST https://login.microsoftonline.com/: {
ā€œRequest Headersā€: {
ā€œacceptā€: ā€œapplication/jsonā€,
ā€œcontent-typeā€: ā€œapplication/x-www-form-urlencodedā€,
ā€œauthorizationā€: ā€œY2xpZW50X2lkOjo0MWVlZWJiZC1lYTdmLTRmNDktYTkzNi0xNjI0YjZjYjljNzI= Y2xpZW50X2lkOjpVSUM4UX5uajNjRGV0UjRYUWxTTmJtMTlXcHl3d2VKTWkuQ3V3YkdBā€,
ā€œuser-agentā€: ā€œPostmanRuntime/7.36.3ā€,
ā€œpostman-tokenā€: ā€œ0afdda48-5d53-42b3-a6b6-83b0c5016773ā€,
ā€œhostā€: ā€œlogin.microsoftonline.comā€,
ā€œaccept-encodingā€: ā€œgzip, deflate, brā€,
ā€œconnectionā€: ā€œkeep-aliveā€
}
}
ā€˜Unable to load access token from responseā€™
GET http://nuc:9653/wordle/getwordleanswers: {
ā€œNetworkā€: {
ā€œaddressesā€: {
ā€œlocalā€: {
ā€œaddressā€: ā€œ10.10.1.8ā€,
ā€œfamilyā€: ā€œIPv4ā€,
ā€œportā€: 54770
},
ā€œremoteā€: {
ā€œaddressā€: ā€œ10.10.1.5ā€,
ā€œfamilyā€: ā€œIPv4ā€,
ā€œportā€: 9653
}
}
},
ā€œRequest Headersā€: {
ā€œauthorizationā€: ā€œBearerā€,
ā€œuser-agentā€: ā€œPostmanRuntime/7.36.3ā€,
ā€œacceptā€: ā€œ/ā€,
ā€œpostman-tokenā€: ā€œe971df37-4c61-4c9e-9b0a-33ad963e3dc6ā€,
ā€œhostā€: ā€œnuc:9653ā€,
ā€œaccept-encodingā€: ā€œgzip, deflate, brā€,
ā€œconnectionā€: ā€œkeep-aliveā€
},
ā€œRequest Bodyā€: ā€œā€,
ā€œResponse Headersā€: {
ā€œcontent-lengthā€: ā€œ0ā€,
ā€œdateā€: ā€œWed, 14 Feb 2024 09:34:36 GMTā€,
ā€œserverā€: ā€œKestrelā€,
ā€œwww-authenticateā€: ā€œBearer error="invalid_token"ā€
}
}

Here is an example of authenticating to Microsoft using a pre-request script.

Slightly different to Alanā€™s example but same concept.

The only thing you will really need to change is the grant type in the body.

let currentDateTime = Date.now();
let tokenExpiry = pm.environment.get("bearerTokenExpiresOn")
// console.log("currentDateTime: " + currentDateTime);
// console.log("tokenExpiry: " + tokenExpiry);
if (!pm.environment.get("bearerToken") || currentDateTime > tokenExpiry) {
    pm.test("Pre-request check for Environment Variables", function () {
        let vars = ['clientId', 'clientSecret', 'tenantId', 'username', 'password', 'scope'];
        vars.forEach(function (item) {
            // console.log(item);
            pm.expect(pm.environment.get(item), item + " variable not set").to.not.be.undefined;
            pm.expect(pm.environment.get(item), item + " variable not set").to.not.be.empty;
        });
        pm.sendRequest({
            url: 'https://login.microsoftonline.com/' + pm.environment.get("tenantId") + '/oauth2/v2.0/token',
            method: 'POST',
            header: 'Content-Type: application/x-www-form-urlencoded',
            body: {
                mode: 'urlencoded',
                urlencoded: [
                    { key: "client_id", value: pm.environment.get("clientId"), disabled: false },
                    { key: "scope", value: pm.environment.get("scope"), disabled: false },
                    { key: "username", value: pm.environment.get("username"), disabled: false },
                    { key: "password", value: pm.environment.get("password"), disabled: false },
                    { key: "client_secret", value: pm.environment.get("clientSecret"), disabled: false },
                    { key: "grant_type", value: "password", disabled: false },
                ]
            }
        }, function (err, res) {
            if (err) {
                console.log(err);
            } else {
                pm.test("Pre-request Microsoft login Status code is 200", () => {
                    pm.expect(res).to.have.status(200);
                    let resJson = res.json();
                    // console.log(resJson);
                    pm.environment.set("bearerToken", resJson.id_token);
                    pm.environment.set("bearerTokenExpiresOn", Date.now() + resJson.expires_in * 1000);
                    // console.log("bearerTokenExpiresOn: " + pm.environment.get("bearerTokenExpiresOn"));
                });
            }
        });
    });
};

You then just set the auth as following.

Thank you Mike Iā€™ll give it a shot

Hi Mike what do I need to put in the scope var ?

Between yours and Allens code Iā€™ve come up with this and it works !!! thanks to you both

pm.sendRequest({
url: pm.environment.get('AzureURL') + pm.environment.get('TenantId') + '/oauth2/v2.0/token',
method: 'POST',
header: 'Content-Type: application/x-www-form-urlencoded',
body: {
mode: 'urlencoded',
urlencoded: [
            { key: "scope", value: pm.environment.get('Scope')},
            { key: "client_id", value: pm.environment.get('ClientId')},
            { key: "client_secret", value: pm.environment.get('ClientSecret')},
            { key: "grant_type", value: "client_credentials"}
            ]
      }},
      function (err, res) {
            if (err) {
                console.log('We have an error ',err);
            } else 
            {
                pm.environment.set('BearerToken', res.json().access_token);
            }});

Glad you got it working.

In relation to scope, this will be down to the particular application you are trying to authenticate against.

Have a look at the Microsoft docs in relation to the particular grant type as it does explain the flows quite well, and includes code examples.

For example.

OAuth 2.0 client credentials flow on the Microsoft identity platform - Microsoft identity platform | Microsoft Learn

In my instance, we were using Azure Websites as a wrapper and the scope is set to ā€œopenid profile emailā€.

You might want to consider extending your code, and including the expiry date\time.

For Microsoft, I donā€™t think it really matters as the tokens last for an hour, and it doesnā€™t really matter if you get a new token each time you run your collection. There isnā€™t a limit as far as Iā€™m aware. It might be different if you use another authentication provider, so its just useful knowing that you can conditionally check the existing token and only get a new token if needed.

I would also recommend having a test in there somewhere, so it only tries to set the bearer token if the access token exists. Otherwise if it doesnā€™t exist, you will just get a fatal error which isnā€™t much use when troubleshooting.

I hear ya Mike but this will only be used to test my self hosted API at home, itā€™s waaay better than jumping to the Linux cli and cutting and pasting from a bash script - thanks again.

1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.