I would like to get the access token from Microsoft teams, when executing it in postman with the same data it works perfectly, when making the post request in react app, it does not work.
This is my code:
useEffect(() => {
debugger;
if (inTeams === true) {
microsoftTeams.authentication.getAuthToken({
successCallback: (result) => {
console.log(result);
const serviceRequest: any = {
client_id: "[client_id]",
client_secret: "[client_secret]",
requested_token_use: "on_behalf_of",
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
scope:
"[scope]",
assertion: result,
};
httpClient.GetAuthenticationToken(serviceRequest).then((res) => {
console.log(res);
});
var querystring = require("querystring");
//...
var asd = querystring.stringify(serviceRequest);
console.log(asd);
axios
.post(
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
asd,
{
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
}
)
.then(function (response) {
console.log(response);
});
microsoftTeams.appInitialization.notifySuccess();
},
failureCallback: function (error) {
console.log(error);
},
});
} else {
setEntityId("Not in Microsoft Teams");
}
}, [inTeams]);
This is what i send(found it in network, the fields in '[]' are replaced by me, because of privacy)
client_id=[client_id]&client_secret=[client_secret]&requested_token_use=on_behalf_of&grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&scope=[scope]&assertion=[assertion]
This is the error i get:
This was in preview in network:
AADSTS9002326: Cross-origin token redemption is permitted only for the 'Single-Page Application' client-type.\r\nTrace ID: ef9c5d80-13d0-4001-898b-7206f4663b00\r\nCorrelation ID: 2c0d0ece-3ce5-4ee6-9cdf-8966f66cee2f\r\nTimestamp: 2022-04-01 10:06:19Z
-------------------------------
UPDATE: Figured it out thanks to the answer :)
I made a back-end method that gets the SSO token and exchanges it for the OBO token. Here is the code:
public static async Task<string> ExchangeForOBOToken(ExchangeOBORequest request)
{
var contentData = new Dictionary<string, string>();
contentData.Add("client_id", request.client_id);
contentData.Add("client_secret", request.client_secret);
contentData.Add("requested_token_use", request.requested_token_use);
contentData.Add("grant_type", request.grant_type);
contentData.Add("scope", request.scope);
contentData.Add("assertion", request.assertion);
using (var httpClient = new HttpClient())
{
using (var content = new FormUrlEncodedContent(contentData))
{
content.Headers.Clear();
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
HttpResponseMessage response = await httpClient.PostAsync("https://login.microsoftonline.com/common/oauth2/v2.0/token", content);
var res= await response.Content.ReadAsStringAsync();
return res;
}
}
}
I just call it from the front end with all the data and return the OBO token :)
CodePudding user response:
So there are a bunch of points in the above:
you haven't actually stated what you need the token for. Presumably from the above, you want the SSO token to be able to call Graph, which is why you want to exchange it for an "on behalf of" (OBO) token - please confirm that though
you do NOT NOT NOT want to be doing the OBO token exchange in your CLIENT code - that is only meant to be happening in the SERVER side, so that these precious tokens can't leak to an attacker. See more in this video and this blog post.
Once your OBO part is moved out to your backend, your code would look much more simple, something like this:
useEffect(() => {
debugger;
if (inTeams === true) {
microsoftTeams.authentication.getAuthToken({
successCallback: (result) => {
// make your call here to your backend, which will in turn: (A) get the OBO token and (B) use it to call whatever you want on Graph.
},
failureCallback: function (error) {
console.log(error);
},
});
} else {
setEntityId("Not in Microsoft Teams");
}
}, [inTeams]);