What Scopes Required For UserInfo Endpoint - Besides 'openid'? - identityserver4

I'm using IdentityServer 4 with .NET Core.
I can successfully log in using grant type ResourceOwnerPassword ('password'), then I immediately call the UserInfo endpoint. That call fails, and when I check the server log I see:
'Scope validation failed. Return 403'
and
'Scopes found on current principal: scope: openid, scope: profile, scope: roles, scope: api1, scope: offline_access'
The docs say 'at least the openid scope is required', which the log shows I have, but the docs also say, right before that, '...Depending on the granted scopes...' - what scopes? Where is it designated what scopes are required by the UserInfo endpoint? I'm assuming I'm missing it/them, but no idea what. I have correct scopes to successfully hit the token endpoint (/connect/token), but not the right scope(s) to successfully call the userinfo endpoint (/connect/userinfo).
Can anyone help?
Thanks!
Buzz

The userinfo endpoint has a minimum requirement for the openid scope.
Here's the test that proves that:
https://github.com/IdentityServer/IdentityServer4/blob/dev/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs#L41

Ok I figured this out - I was missing an AllowedScope on the call to the UserInfo endpoint. When I added the scope here in the Startup.Configure() method it worked:
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://localhost:5000/",
AllowedScopes = { "api1", "WebAPI" },
RequireHttpsMetadata = false
});
The thing I don't understand is how the login itself was working. The scopes are sent in on the call to login (/connect/token) - and that succeeded. I thought these scopes were for authentication, as the name for this class here is '..AuthenticationOptions'. My guess is these are options during login but not for login, and they're only used when you go out to access a resource, such as /connect/userinfo. Maybe someone who knows can confirm this.
Thanks for your help!
Buzz

Related

azure msal-brower with nextJs: passing only one scope to the API

I've got a SPA calling an API. The user authenticates using Azure AD and I'm exposing the API with a custom scope (access).
I report below the responses based on different scopes:
scopes = ['access'] => Authorised. Scope in the passed token is: "access"
scopes = ['user.read'] => Not authorised. Scope in the passed token is: "openid profile User.Read email"
scopes = ['access', 'user.read'] => Authorised. Scope in the passed token is: "access"
scopes = ['user.read', 'access'] => Not authorised. Scope in the passed token is: "openid profile User.Read email"
scopes = ['profile', 'email', 'openid', 'access'] => Authorised. Scope in the passed token is: "access"
I don't think it's normal behaviour because I couldn't find any reference around it. What if I need, in the API, the info coming from the User.Read as well?
Dep version: "#azure/msal-browser": "^2.26.0"
I tried to reproduce the same in my environment and got the same results.
When I passed ['access', 'user.read'] ,I got token for only access scope like below:
Please check the aud (audience) claim of the token you are generating.
If you are giving access as your scope, your aud will be api://your_app_id.
If you are giving user.read as your scope, your aud will be 00000003-0000-0000-c000-000000000000 that means graph.microsoft.com.
If you are giving 2 different scopes like ['access', 'user.read'], it will only consider first scope and generate token for that specific audience like below:
As mentioned by Juunas in this SO Thread, access token is valid for one API only based on the audience.
If you want the info coming from the User.Read, you need to generate two tokens, one for your API scope (access) and another for Graph API scope (user.read).
For more in detail, please refer below link:
azure - Passing multiple scope values to Oauth token endpoint - by Hari Krishna

Cannot get Username / given_name when using angular-oauth2-oidc and Identity Server 4

I am following the Implicit Workflow example from the angular-oauth2-oidc documentation.
Everything works well in my Angular app, and I can login (during which I am redirected to Identity Server), get my token and use this token to access my Web Api.
However, I have noticed that the "given_name" claim is null, and therefore, the username is not displayed on the login page. Specifically, the following method from the sample code appears to return null:
public get name() {
let claims = this.oauthService.getIdentityClaims();
if (!claims) return null;
return claims.given_name;
}
I thought perhaps this was a problem with permissions, but my scope is set to:
scope: 'openid profile email api1',
Any idea what I need to change to get this "given_name" claim?
For those who encountered the same issue. You can fix it by adding this line AlwaysIncludeuserClaimsInIdToken=true in the client settings on identity provider side.
OauthService.getIdentityClaims() is a Promise and holds UserInfo you can extract the name field with braces, so your function should be:
public get name() {
let claims = this.oauthService.getIdentityClaims();
if (!claims) return null;
return claims['name'];
}
The answer marked as "Best answer" is not correct. Get the user claims in the 'idtoken' will cause that the 'idtoken' be very big and then you may exceed the size limit.
The correct implementation is to use the 'UserInfo' Endpoint and then use the method 'loadUserProfile':
Example:
getUserClaims() {
const user = this.oauthService.loadUserProfile();
console.log(user, user);
}
I had the same issue, in my case with an error displayed on the browser console, saying that Request was blocked by Security Policy.
even having the AllowAnyOrigin() method called in startup, I lacked to get the header allowed. So when in my angular aap i call the loadUserProfile method via the
token_received event, it sends some headers that were not allowed.
Finaly this fix my issue:
app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader());
Don't forget calling that before usemvc

How to set the Access-Token for the password reset in LoopBack with the AngularJs SDK

My Project is based on the
Loopback Getting Started Tutorial 2
I use the AngularJs SDK on the Client-Side and I want to implement the "Password-Reset"-Function.
First there is the /reset-password view, where you can enter your email address and ask for another password.
Then you get a link send per email that directs you to /set-new-password/{{accessToken}}/{{userId}}
On this view, the user enters the password and submit it. Afterwards it should find the User by Id and update its password.
But for User.findById and User.updateById I need the access-token in the Request-Header.
"Normally" the Request-Header always contains the access-token after the login. But since it's a password-reset, I'm not logged in.
I can access the access-token via $stateparams, but how can I set it in the Request-Header,so I can still use the AngularJs-SDK?
(I hope everything is clear. English is not my native language)
Edit: I have found someone with nearly the same question here. The not accepted answer works for me now.
EditEdit: Doesn't work always.. Sometimes it doesn't change the "authorization"-parameter in the Header. Can't figure out why
The solution with the LoopBack AngularJs SDK
In your angularJs controller
.controller(function (UserAccount, $location, LoopBackAuth, $scope) {
var params = $location.search();
var access_token = params.access_token;
$scope.reset = function(inputs) {
LoopBackAuth.setUser(access_token);
UserAccount.setPassword({ newPassword: inputs.newPassword });
}
})
You need to implement error control and ideally check the password twice before sending.

If I use $firebaseAuth.$createUser will that populate the auth variable for security rules?

I am using the $firebaseAuth.$createUser() method to register a user to my firebase backend, I then immediately try to create a /profile/ for the user. In 'profile' security rules I have rule that only the current user can create/edit their profile.
"profile": {
".read": true,
"$profileId":{
".write": "auth.uid == $profileId"
}
}
However it appears because I do this right after I call $createUser() using the then() chainining method that the auth variable isn't correct when the security rules process. Do I need to call an auth() method or something after I call $createUser() ??
Ok, after digging through the documentation, I found that $createUser() does NOT authenticate the user. Once the account is created, the user may be authenticated with the authWithPassword() function.

What are scope values for an OAuth2 server?

I'm facing a difficulty to understand how scopes work.
I found here a small text that describes the scopes of stackexchange api but i need more information on how they work (not specifically this one...). Can someone provide me a concept?
Thanks in advance
To authorize an app you need to call a URL for the OAuth2 authorization process. This URL is "living" in the API's provider documentation. For example Google has this url:
https://accounts.google.com/o/auth2/auth
Also you will need to specify a few query parameters with this link:
cliend_id
redirect_uri
scope: The data your application is requesting access to. This is typically specified as a list of space-delimited string, though Facebook uses comma-delimited strings. Valid values for the scope should be included in the API provider documentation. For Gougle Tasks, the scope is https://www.googleapis.com/auth/tasks. If an application also needed access to Google Docs, it would specify a scope value of https://www.googleapis.com/auth/tasks https://docs.google.com/feeds
response_type: code for the server-side web application flow, indivating that an authorization code will be returned to the application after the user approves the authorization request.
state: A unique value used by your application in order to prevent cross-site request forgery (CSRF) attacks on your implementation. The value should be a random unique string for this particular request, unguessable and kept secret in the client (perhaps in a server-side session)
// Generate random value for use as the 'state'. Mitigates
// risk of CSRF attacks when this value is verified against the
// value returned from the OAuth provider with the authorization
// code.
$_SESSION['state'] = rand(0,999999999);
$authorizationUrlBase = 'https://accounts.google.com/o/oauth2/auth';
$redirectUriPath = '/oauth2callback.php';
// For example only. A valid value for client_id needs to be obtained
// for your environment from the Google APIs Console at
// http://code.google.com/apis/console.
$queryParams = array(
'client_id' => '240195362.apps.googleusercontent.com',
'redirect_uri' => (isset($_SERVER['HTTPS'])?'https://':'http://') .
$_SERVER['HTTP_HOST'] . $redirectUriPath,
'scope' => 'https://www.googleapis.com/auth/tasks',
'response_type' => 'code',
'state' => $_SESSION['state'],
'approval_prompt' => 'force', // always request user consent
'access_type' => 'offline' // obtain a refresh token
);
$goToUrl = $authorizationUrlBase . '?' . http_build_query($queryParams);
// Output a webpage directing users to the $goToUrl after
// they click a "Let's Go" button
include 'access_request_template.php';
The set of query string parameters supported by the Google Authorization Server for web server applications are here:
https://developers.google.com/accounts/docs/OAuth2WebServer?hl=el#formingtheurl

Resources