Does User.Read "contain" the permissions email openid and profile? I've found that apps that are requesting the 3x scopes, can instead accept just the User.Read permission and still function equivalently
At work I'll get requests from the business to help them setup SSO using OIDC, and I'm not actually sure what permissions I should be giving them. Seems like either option works but I'd like to better understand what's happening
See my observations below:
I've created a basic Function App, and configured it to use OpenID Connect Image
My App Registration already has the User.Read permission with admin consent, so when I log into my Function, there's no issue.
Image
However, after removing the User.Read permission and logging in, I now get a permissions request prompt Image
And after consenting to the permissions, I can now see that email openid and profile permissions were added Image
Even more interesting, the permissions in the request prompt correlate to openid and offline_access, but offline_access wasn't added, while email and profile weren't in the request
I did find a similar question, but the accepted answer doesn't seem to align with what I see here
Generally I would favour the OAuth standard design where fields like these are Personally Identifiable Information (PII). So each app should only use the smallest scope it needs, as an information disclosure best practice. See also this Curity article.
Name
Email
Phone
Address
The Graph API can also be used with standard scopes, as in step 11 of this blog post of mine, where I wanted to get hold of user info in an API. So if this works for you I would prefer it. Personally I also prefer standard scopes so that my application code is portable.
Microsoft's design is based on each API requiring a different access token, the resource indicators spec. It is interesting, though perhaps not always intuitive. I am no expert on Azure AD though, and there may be some intended usage I do not understand.
User.Read is a scope intended to be used when requesting an access token for the Microsoft Graph API. It grants privileges to read the profile of the signed-in user only. A separate call to the Microsoft Graph API is required to retrieve the profile.
openid, email, profile and offline_access are OpenID Connect scopes:
openid is used to request an id token.
offline_access is used to request a refresh token which can later be used to get a new access token.
email to request an email claim.
profile to request several user claims (Eg.preferred_username).
Both email and profile can be used to augment information available in the UserInfo endpoint, however, it is recommended to use the id token which is already a superset of the information available at the aforementioned endpoint.
Related
I have created custom policies with SSO and account migration (you can view them on GitHub here, Note: I removed/edited values for security reasons). I want users to be able to sign in with a social provider OR local account for the first time. I will then migrate their account from the legacy identity provider to AAD B2C. The following goes wrong at the moment though.
The biggest problem is when the account is migrated and the user can sign in, then when trying to link social accounts, I get the following error.
AADB2C90051: No suitable claims providers were found.
Correlation ID: 4491cd4a-2f98-4a86-8d65-da3f7f26e890
Timestamp: 2022-11-20 10:38:05Z
The weird thing is, if I first sign-in using Google or Facebook (which then migrates the account) then sign-in with Microsoft or the local account, it will work. But when first signing in with either Microsoft or a local account, I get the error.
I've seen this and other posts but cannot find what I am missing. I know the policies are very big, so to start, look in CUSTOM_USERJOURNEY.xml for ProvisionOrSignInNewSocialAccount on GitHub.
By default, the hasPassword property doesn't exist by for existing local B2C user profiles. It is introduced by the linking Custom Policy. You will need to manually (or by script) add value true for that property, and it will start working.
You can use Graph API to add value, so basically PATCH to user endpoint:
PATCH /v1.0/users/12bda93c-f782-431c-b962-52c5304c0668 HTTP/1.1
Host: graph.microsoft.com
Content-Type: application/json
Authorization: Bearer eyJ0...
{
"extension_67a963aa6ce74511923b85511f0f8dad_hasPassword" : true
}
See here for full discussion: https://bytemeta.vip/repo/azure-ad-b2c/samples/issues/430
Slightly related to this question, but scenario is different: AAD-FindLocalAccountWithSocialEmail produces No suitable claims providers were found
I have 3 applications:
An IdentityServer4 API which provides Google authentication and also provides an access token to authorize the resource API.
A simple Resource API which provides some data from DB.
A simple Client in React which have 4 buttons:
Login, for Google auth
Logout
Get data - a simple request with the access token to the Resource API and gets the data from Db
Get user data - returns user profile and token (for debug purpose)
I didn't put any sample code because my problem is not code related, it's knowledge that I'm missing and I ask for guidance.
The workflow is working just fine: the user press the Login button, it is redirected to IdentityServer4 API for Google Auth. From there it is redirected to a Callback Page from the Client and from there to the Index page. I receive the user data and the token, I can request data from the Resource API and it's working.
My problem is: How do I give a Role to the Google Users ?
I don't have users saved in DB. I want three types of Users: SuperAdmin, Admin, Viewer and each of these roles have limited Endpoints which can access.
For limiting their access I saw that I can use Claims-based authorization or Role-based authorization.
So, my question is how ca I give a Google User who wants to login in my app, a specific Claim/Role ? What is the workflow ? I must save it first in DB ? Or there exists a service from Google where I can add an email address and select a Role for that address ?
Thank you very much !
After you get the response from Google in your callback you can handle the user and do what ever you want to do with it. Below are the some typical tasks that you can do in callback that I took from documentation page of identityserver4 link:
Handling the callback and signing in the user
On the callback page your typical tasks are:
inspect the identity returned by the external provider.
make a decision how you want to deal with that user. This might be
different based on the fact if this is a new user or a returning
user.
new users might need additional steps and UI before they are allowed
in.
probably create a new internal user account that is linked to the
external provider.
store the external claims that you want to keep.
delete the temporary cookie
sign-in the user
What I would do is creating an new internal user account that is linked to the external provider and add a role to that user.
If you don't want to save users in db, you can add an extra claim to user in callback method and use that claim in token. and i think this link will help with that.
I have an existing signup/login system: a user enters an email and password. The password is hashed. I store it in a database.
When a user logs in, they entire their email and password. The password is hashed, and I look up the email in the database and check that the email matches. If it does, they are logged in.
I want to add a system to let users login with a 3rd party OAuth, such as GitHub. I have that setup, but I am unsure what data to store in my database.
I was thinking I take their GitHub email as the email and then use the access token for their GitHub as the password (so I would hash it and store it.)
I think this would work, but I am worried that the access tokens could change meaning they would be locked out of their account.
If I shouldn't be using the access token as a password, what should I be using? I need to store the user's email on my database but that requires a password currently, which I can't get if they use GitHub login.
(Note that when the user logs in, I call my backend to generate an access token (JWT) which I can use to require their user details and then store it in local storage. I'd like to then be able to do the same thing with with GitHub or whatever.)
oAuth is usually for authorization. Meaning, you get an access token from the authorization server, the resource server validates it and let the user access to the data.
In your case, you "do not really need" the access token - you want to use oAuth just for the authentication. Web-applications (like StackOverflow) do this to "save the trouble" of handling the authentication flows. Meaning, if I write a secured application, I need to implement somehow the create account flow, login flow, forgot password, etc. When you use a 3rd-party authentication, you save this trouble.
However, your application does need some user-id to perform actions; so you must create a user-id in you app when a user appears for the first time. Since then, you do not need to worry about password-expiry, forgotten-password and even not for the login. When the user logs-in, you get the access token and all you need to do is to get yours app' user-id from it.
Thus, I do not see a reason why you need to store a 'password', or the access token.
Hope that makes sense.
What you are looking for is actually OpenID Connect - it's an authentication framework built on top of OAuth, which lets you log in users using external Identity Providers, like Github.
When a user logs in using GitHub then you will receive an id_token in a form of a signed JWT. You can easily verify the authenticity of the JWT - so you can easily make sure that the id token really comes from Github and presents real data. Usually one of the information in the id token will be the user's email. You can use that to look up the user in your database. You don't need any password in this case.
So, you will have two ways of finding a user in your DB - either through comparing the email and password, or by looking up the user's email from a validated id token from Github.
Is it possible, while acquiring an access_token (Client Credentials grant), to instruct AAD to inject certain custom claims with certain values into the access_token being issued?
I need it to avoid sending extra context information to my service through such a "disconnected" means as HTTP Header for instance. Instead I want the token signed by AAD and containing everything AAD stamps into it by default plus some small pieces of information controlled by the application acquiring the token. All this will help my service to apply proper authorization once this token is received by the service.
I looked at the above, and I am clear that you are not looking for claims augmentation as it was described in the blog.
As I understood, you are looking for the right way to authorized your application using AAD tokens.
If my understanding is correct here is my answer.
It took me quite sometime to remember how I did it before and the caveat was missing the graph permissions for:
Directory.AccessAsUser.All
Directory.Read.All
Directory.ReadWrite.All
Now let me type down the steps one by one, but care less to the order of these steps may not be correct, just do the steps in any order you want.
Step 1: In AD, in the App registration
Register your Web Application,
Copy the Client_ID
Step 2: Go to Expose an API
Add a scope or more (This is what you are going to see as a claim and role in the token)
Add the client Client_ID
Note: this is basically for 2 applications one calling another, but in this example and your case, you have one web application that needs to authorize on itself.
Next: In the API permissions
THIS IS A MUST grant admin consent delegated permissions for MicrosoftGraph
Directory.AccessAsUser.All
Directory.Read.All
Directory.ReadWrite.All
Additionally: Give permission to the scope that you added.
Then: In the App roles:
Add the Application roles
Then: In the Enterprise Applications:
Assign that role to the users or groups that you want to access this.
Finally: In the application configuration file
Update the Client id
You are done.
I hope that was what you were looking for.
When performing authentication using the OpenID federated login on GAE, my user object has the following properties:
Nickname: http://wordfaire.com/openid?id=103539105724544727060
email: sudhir.j#wordfaire.com
From the docs,
email()
Returns the email address of
the user. If you use OpenID, you
should not rely on this email address
to be correct. Applications should use
nickname for displayable names.
Obviously, this advice isn't working out very well. So how then can I get an authoritative email handle to associate with a particular OpenID provided by any Google Apps or other domain? I really need the email ID because things like invitations and sharing / access control all function via email ids.
If you need a valid email for OpenID users, ask the user to supply one the first time they log in, and store it yourself along with their user object.
Since anyone can create an OpenID provider, it's not safe to assume that the provider has already gathered a valid address.