ClientConfigurationError Microsoft OAuth Flow - oauth-2.0

I am implementing the Microsoft Auth code flow but I am stuck with this error.
Based on this code example, here is how I am initializing the client:
const config = {
auth: {
clientId: process.env.MICROSOFT_CLIENT_ID,
authority: process.env.MICROSOFT_AUTHORITY,
clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
},
};
const cca = new msal.ConfidentialClientApplication(config);
And later I want to create an authentication URL to redirect the user to:
const authCodeUrlParameters = {
scopes: ["user.read"],
redirectUri: "http://localhost:8080/oauth/microsoft",
state: 'state_here',
};
cca
.getAuthCodeUrl(authCodeUrlParameters)
.then((authCodeUrl) => {
return authCodeUrl;
})
.catch((error) => console.log(JSON.stringify(error)));
But I am getting this error: {"errorCode":"empty_url_error","errorMessage":"URL was empty or null.","subError":"","name":"ClientConfigurationError"}
Based on the docs about errors, it looks like it's thrown before requests are made when the given user config parameters are malformed or missing.
Anybody can spot where the configs are malformed?

The error is because of the missing configuration requirements in the application.
And most importantly , check the authorization request url for missing parameters like state and nonce and the redirect url.
Here request URL may require state and nonce parameters form cache as part of authCodeUrlParameters to construct the URL.
In authCodeUrlParameters see which of them is missed as they may lead to url to null.
You try to give your domain in knownAuthority
Ex:
auth: {
clientId: 'xxxx-xx-xx-xx-xxxxx',
authority: '<give authority>',
knownAuthorities: ['<domain here>']
redirectUri: 'https://localhost:8080'
},
cache: {
cacheLocation: "sessionStorage",
storeAuthStateInCookie: false,
secureCookies: false
},
Please make sure the redirect url is in correct format:
See Redirect URI (reply URL) restrictions - Microsoft Entra | Microsoft Learn
After setting the correct url, I could get proper response

Related

MSAL - Network request failed. Please check network trace to determine root cause

I am trying to use MSAL for node.js for OAuth 2.0 authentication, and I'm getting an error when calling acquireTokenByAuthCode.
Network request failed. Please check network trace to determine root cause. | Fetch client threw: Error: HTTP status code 400 | Attempted to reach: https://login.microsoftonline.com/{myTenantId}/oauth2/v2.0/token
Client instance:
const msal = new ConfidentialClientApplication({
auth: {
clientId: process.env.MS_CLIENT_ID,
clientSecret: process.env.MS_SECRET,
authority: process.env.MS_AUTHORITY
}
})
Login route:
const uri = await msal.getAuthCodeUrl({
responseMode: 'query',
redirectUri: `${process.env.APP_URI}/auth/code`,
scopes: ['user.read']
});
res.redirect(uri);
Token route (/auth/code):
try {
const {
accessToken,
} = await msal.acquireTokenByCode({
scopes: ['user.read'],
code: req.query.code,
redirectUri: `${process.env.APP_URI}/auth/code`,
});
res.cookie('token', accessToken);
res.redirect('/');
}
catch(e) {
res.status(401).send(e);
}
I can retrieve an auth code just fine, but I get the error when trying to get the token in the last snippet.
Make sure your clientSecret is correct. I just had this same issue and realized I was using the ID of the secret as opposed to the actual secret itself.
I fixed it. The Application was just missing the openid permission.

Either scp or roles claim need to be present in the token using when application permissions to read sharepoint sites

I created an app in Azure and set it up to use Access and ID tokens.
I want to connect to different tenants and read SharePoint sites. Here are the permissions I've requested and received Admin Consent for:
For now, I have set up an App Secret but I do plan to move to a certificate later.
I have this code to get the access token and I do get an access token back:
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
params.append("scope", "https://graph.microsoft.com/.default");
params.append("client_id", process.env.client_id);
params.append("client_secret", process.env.client_secret);
var url = `https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token`;
const response = await fetch(url,
{
method: 'POST',
body: params,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}
);
However when I try to read the root site below
var url = "https://graph.microsoft.com/v1.0/sites?search=*";
const response = await fetch(url,
{
method: 'GET',
headers: { 'Authorization': `Bearer ${access_token}` }
}
);
I get this error:
error: {
code: 'AccessDenied',
message: 'Either scp or roles claim need to be present in the token.',
innerError: {
'request-id': 'ec47913f-2624-4d1c-9b27-5baf05ccebfd',
date: '2019-08-16T14: 15: 37'
}
}
I checked the token at https://jwt.io/ and indeed I do not see any entry for roles or scp.
It looks like I missed a step but I cannot figure out which step.
I am getting the token like this:
https://login.microsoftonline.com/${tenant}/oauth2/v2.0/token
What am I doing incorrectly?
The first thing to understand is that you cannot receive both Application and Delegated permissions in the same token, it is an either/or scenario. Which type you receive depends entirely on which OAuth Grant you used to request the token:
Authorization Code and Implicit return Delegated tokens with an scp property
Client Credentials return Application tokens with a roles property
The second thing is that you've requested scopes to two different APIs. Based on what you've selected, you won't have access to SharePoint through the Microsoft Graph because you've only requested access to the legacy SharePoint API. More importantly, you've only requested the Delegated User.Read scope for Graph so when you use Client Credentials to obtain the token, that token won't have any permissions.
In order to obtain an Application token for reading SharePoint sites, you'll need Sites.Read.All Microsoft Graph Application permission selected.

Reproducing an ADAL.JS-authenticated request in Postman

I have a .NET Web API and a small vanilla-JS app using ADAL.js, and I've managed to make them talk nicely to each-other and authenticate correctly.
If I console.log the token returned from adalAuthContext.acquireToken() and manually enter it as Authorization: Bearer {{token}} in Postman, I can also get a valid, authenticated, response from my backend.
However, I can't figure out how to configure Postman's built-in OAuth2.0 authentication UI to get me tokens automatically. I have managed to get tokens in several ways, but none of them are accepted by the backend.
How do I configure Postman to get a token the same way the ADAL.js library does?
For completeness, here's some code:
Backend configuration:
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters { ValidAudience = "<app-id>" },
Tenant = "<tenant>",
AuthenticationType = "WebAPI"
});
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
ADAL.js configuration:
const backendUrl = 'http://localhost:55476';
const backendAppId = '<app-id>';
const authContext = new AuthenticationContext({
clientId: backendAppId,
tenant: '<tenant>',
endpoints: [{ [backendAppId]: backendAppId }],
cacheLocation: 'localStorage'
});
Actually making a request:
authContext.acquireToken(backendAppId, (error, token) => {
// error handling etc omitted
fetch(backendUrl, { headers: { Authorization: `Bearer ${token}` } })
.then(response => response.json())
.then(console.log)
})
So since the Azure AD v1 endpoint is not fully standards-compliant, we have to do things in a slightly weird way.
In Postman:
Select OAuth 2.0 under Authorization
Click Get new access token
Select Implicit for Grant Type
Enter your app's reply URL as the Callback URL
Enter an authorization URL similar to this: https://login.microsoftonline.com/yourtenant.onmicrosoft.com/oauth2/authorize?resource=https%3A%2F%2Fgraph.microsoft.com
Enter your app's application id/client id as the Client Id
Leave the Scope and State empty
Click Request token
If you configured it correctly, you'll get a token and Postman will configure the authorization header for you.
Now about that authorization URL.
Make sure you specify either your AAD tenant id or a verified domain name instead of yourtenant.onmicrosoft.com.
Or you can use common if your app is multi-tenant.
The resource is the most important parameter (and non-standards-compliant).
It tells AAD what API you want an access token for.
In this case I requested a token for MS Graph API, which has a resource URI of https://graph.microsoft.com.
For your own APIs, you can use either their client id or App ID URI.
Here is a screenshot of my settings:

invalid_grant on OAuth2 request when obtaining access_token from SSO in App

I have an iOS App with an Uber API integration where I use SSO to authenticate the user and then save the accessToken & refreshToken locally on my device. Then I'm calling my server who uses a javascript background function to call the node-uber (https://www.npmjs.com/package/node-uber) library to make a request to Uber.
So far, I'm trying to set up the uber client with my 2 local tokens from the SSO login like this:
var uber = new uberClient({
client_id: '...',
client_secret: '...',
server_token: '...',
name: 'My App',
sandbox: true, //optional
access_token: accessToken,
refresh_token: refreshToken
});
afterwards I want to call the uber.requests.getEstimatesAsync endpoint like this:
uber.requests.getEstimatesAsync({
"start_latitude": pickupLocation["lat"],
"start_longitude": pickupLocation["lng"],
"end_latitude": dropoffLocation["lat"],
"end_longitude": dropoffLocation["lng"]
})
.then(function(res) {
console.log(JSON.stringify(res));
})
.error(function(err) {
console.error(err);
});
})
Though every time I get an "invalid_grant" error 400 while doing this. Did I make a mistake authenticating myself or setting up the Uber client wrong? Is it even possible to use my SSO accessToken & refreshToken then on the uber client, which does a OAuth2 authentification? I thought that both access and refresh token should probably be the same what Uber sends back to be for SSO & OAuth2.
I'm using a Developer account for doing this, therefore I should actually have all the required permissions for the request endpoint, but I also obtained them previously in the App correctly.
This thread on the official uber documentation explains potential reasons but I guess they don't really apply to my case, do they? https://developer.uber.com/docs/riders/guides/authentication/introduction#common-problems-and-solutions
Any security expert here who can help?
Best regards,
Matt
P.S.: I also posted this question on the Uber library I'm using for making those requests, but nobody seems to be able to help me there so far. https://github.com/shernshiou/node-uber/issues/70
Edit: The following picture shows my authentication setup so far:
I found a solution. I think was a problem with the library itself. Because once I made the request with http with the "request" library (https://github.com/request/request) it worked. Include for that at the top of your code:
var request = require('request');
Both OAuth2 and SSO accessToken worked. You should give the method a pickupLocation with latitude and longitude and your obtained accessToken from Uber like this:
function getAllAvailableUberProducts(pickupLocation, accessToken){
var lat = pickupLocation["lat"].toString();
var lng = pickupLocation["lng"].toString();
var options = {
uri: "https://api.uber.com/v1.2/products?latitude="+lat+"&longitude="+lng,
method: 'GET',
headers: {
"Authorization": "Bearer " + accessToken,
"Accept-Language": "en_US",
"Content-Type": "application/json"
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(JSON.parse(body).products);
} else {
console.log(error);
}
});
}
I hope this helps someone.

Dont understand Google Drive oAuth 2.0

I need oAuth2 on google drive . But i cant get token. Which parameters is wrong ? Google documentation API cant help me for understanding what is wrong .
I do fetch request.
const options = {
method: 'post',
client_id: '{EXAMPLE}deajshot.apps.googleusercontent.com',
redirect_uri: 'https://drive.google.com/open?id={EXAMPLE}',
scope: 'https://www.googleapis.com/auth/drive.metadata',
prompt: 'none',
mode: 'no-cors',
response_type: 'token'
};
fetch('https://accounts.google.com/o/oauth2/auth',options)
.then(function (response) {
console.log(response);
})
Now i have error - 400. That’s an error.
Error: invalid_request
Required parameter is missing: response_type;
By your code example , you first need to get a code and then request a access token.try to follow this tutorial: https://developers.google.com/identity/protocols/OpenIDConnect#authenticatingtheuser
You have there a request for example:
https://accounts.google.com/o/oauth2/v2/auth?
client_id=424911365001.apps.googleusercontent.com&
response_type=code&
scope=openid%20email&
redirect_uri=https://oauth2-login-demo.example.com/code&
state=security_token%3D138r5719ru3e1%26url%3Dhttps://oauth2-login-demo.example.com/myHome&
login_hint=jsmith#example.com&
openid.realm=example.com&
hd=example.com
After this , with your 'code' parameter you get you could make request to get a access token (you have there also a example of this request )
Good luck

Resources