I am trying come up with a bash script to register an application in Azure AD using the /beta/applications endpoint from Microsoft Graph.
To call /applications, I would need to get an access token.
Is it possible to get an access token for Microsoft Graph using just email address/password (Without a client-id)? I am looking for something like "Resource Owner Password Credentials Grant Flow" mentioned in OAUTH2 spec.
Any other alternative I can look into. I want to write a simple script that would manage application registration and any updates to the application in future.
Yes, there are several means of running a script against the Microsoft Graph API without a user present:
AD supports the resource owner credential grant that you described in your question. This flow doesn't support some new auth features like multifactor auth and you'll have to be very careful about securely storing your credentials.
The other option is to use V2 auth client credential flow. In this case, the tenant admin consents to the application on behalf of the tenant. Afterwards, the application can run without a user present. One benefit of this flow as opposed to the V1 resource owner credential grant is that you pass a client credential which can be revoked and re-generated if needed (rather than dealing with raw user credentials).
Related
We are trying to connect a javamail (1.6) client to our office365 mailbox hosted on office365 using OAUTH2 authentication.
No matter what we do, we keep getting A1 NO AUTHENTICATE failed.
We have registered our application with
API Permission
we followed all instructions stated at
https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth
including running the powershell commands to create the principal using the app id and object id, and we granted the app full access to emailbox we want to access.
For authentication we do an HTTP POST as following which generates an access token
This is a client credentials flow with shared secret as explained here
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
https://login.microsoftonline.com/{our tenant id}/oauth2/v2.0/token
with
client_id=...
client_secret=...
grant_type=client_credentials
scope=https://outlook.office365.com/.default
our javamail configuration
mail.store.protocol="imap"
mail.imap.host="outlook.office365.com"
mail.imap.port="993"
mail.imap.ssl.enable="true"
mail.imap.starttls.enable="true"
mail.imap.auth="true"
mail.imap.auth.mechanisms="XOAUTH2"
mail.imap.user="<email box>"
then in our java code we connect the store with the access token obtained from the above HTTP POST
store.connect(host, user, oauth2_access_token);
We also tried this powershell script, which returns the same error
https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1
I do not believe that problem is specific to JavaMail.
It is extremely difficult to determine if an access token has the correct rights or there is something else that prevents the authentication
What else can we try?
Update 1
If we use the powershell script
https://github.com/DanijelkMSFT/ThisandThat/blob/main/Get-IMAPAccessToken.ps1
passing only the client id and the redirectUri the script prompts me for approval and it succeeds
but if we use clientsecret authorization fails
Update 2
I can successfully use javamail with the access token generated by the powershell script.
Clearly the token created with the clientsecret does not have enough rights to access IMAP or the mailbox
I start to wonder if token requests using client secret do not work because our Azure Active Directory has "security defaults" enabled.
May be MFA is enforced therefore any non-interactive requests are blocked
Update 3
https://jwt.ms allows to decode access tokens
The token created with just the clientid (code grant flow) is very different from the one created with the client_secret (client credentials flow).
In token from "code grant interactive" there is an attribute called "scp" Set of Scopes, which lists scopes regardless of what I have in my client app API permission ????
"scp": "IMAP.AccessAsUser.All Mail.Read Mail.Read.All Mail.Read.Shared Mail.ReadBasic User.Read"
The second token from the client credentials flow, has an attribute "roles", but does not have scopes
"roles": ["IMAP.AccessAsApp"]
RESOLVED!
looking at the access token we noticed that the client credentials flow subject (sub) was an id that we did not setup.
Here is the catch: when creating the service principal using powershell in exchange online, for serviceid you have to use the objectid of the enterprise application.
New-ServicePrincipal -AppId {clientid} -ServiceId {enterprise application objectid} -Organization {tenantid}
When creating an app registration Azure AD, you also create an enterprise application
The application object id is different from enterprise application object id.
The client credentials flow uses the enterprise application object id as the user asking for authorization.
The same for granting access to the mailbox using powershell
Add-MailboxPermission -Identity {email} -User -ServiceId {enterprise application objectid} -AccessRights FullAccess
it is unfortunate that the authentication process is so cumbersome
My two cents on this , if you are still facing authentication failure from javamail trying to connect to mailbox and read emails, First and foremost make sure the application setup in azure active directory has below permissions.
IMAP.AccessAsApp
Mail.Read
Mail.Send (For Sending)
Secondly, Create service principal with the enterprise application id as mentioned in the original post.
Once done check here if your generated token has all the roles you have assigned.
Even if you assigned necessary roles and you can able to connect to mailbox via powershell still you might get AUTHENTICATE failed from javamail because you might be using this property (mail.imap.auth.mechanisms) wrongly , replace mail.imap with mail.imaps and it should solve the problem.
"mail.imaps.auth.mechanisms"="XOAUTH2"
"mail.imap.host"="outlookoffice365.com"
"mail.smtp.port"=993
"mail.store.protocol"="imaps"
session.getStore("imaps")
store.connect(host,port,user,token)
Good luck !!
I am reading documents for Microsoft Identity Platform to implement api and protecting it by using Microsoft Identity platform and I do understand some what OAuth code Grant flow and Client Credential flow (for daemon apps).
Now when I am reading the documents it is keep mentioning authorization on 'behalf of user' and and 'behalf of itself'. So my question is "on behalf of user" is same as Code Grant flow?. Similarly if client credential flow is "on behalf of itself'.
If not then what is the difference between 'On behalf of user' vs Code grant flow.
Really want to understand as it keeping me in confusion.
Thanks
Azure AD supports the following OAuth flows/grants:
Implicit
Authorization code (with/without PKCE)
On-behalf-of
Client credentials
Device code
Resource owner password credentials
Refresh token
Link to docs: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols
In most of these, the application will get an access token that allows it to perform requests on behalf of the signed in user.
The access token contains both information of the app that requested token but also the signed in user's information.
This allows the target API to check both the application's access (scopes aka delegated permissions) and the user's access (roles/other form of access control).
The "on-behalf-of" flow might be a bit confusing here, but it has a specific purpose: exchange an access token obtained with one of the other flows (except client credentials) for a new access token.
It is used in scenarios where a client app uses e.g. authorization code flow to call API A, and API A wants to then call API B on behalf of that same user.
Client credentials flow is the only different one; when using it an application only provides its own credentials and a user is not involved.
Thus the access token only contains application information, and the application will perform requests as itself.
The target API will usually only check the roles in the token (application permissions, app roles with allowed member type application), though it can also check the id of the calling app if it has a list of allowed applications stored somewhere.
Does keycloak provide a way to support Personal Access Tokens, similar to Github, when I am using Keycloak to handle authentication and using the tokens it issues to secure my API? When my application is using a web browser then logging in via OIDC flow works fine, but how can I handle login from a CLI or a headless API script for my application?
I could support a password flow where I get back a JWT token after providing a username and password, but I assume once the user has configured 2FA or if they are using SAML on the backend then all bets are off as a username and password would not get you access. This is exactly why Github offers personal access tokens. Is there some way to implement something like this using Keycloak or do we have to build it in our own application and then accept those tokens in addition to the JWT.
What I would envision is Keycloak being able to generate and store personal access tokens in its user store that a user could generate and revoke via the UI that Keycloak provides to the user. My CLI could then use this token to obtain a JWT and then proceed with calling my API the same way a web browser or other client would.
Some support for utilizing OTP during CLI scripting was added in recent Keycloak releases. I've not played with it so far, so i can't present you any recipes. Try to start at Authentication -> HTTP challenge Flow settings.
Regarding to users token you can implement required functionality as an SPI extension to Keycloak (see Server Development section in docs). From my point of view there should be two components:
User token issuer
Custom authenticator that will be used in authentication flow for your client
Here is rough example:
Let User tokens be like UUID strings, so all user tokens could be stored in user attributes (Attributes tab in user's settings Admin UI).
Some of your APIs could introduce dedicated endpoint that will accept valid Access Token< generate new UUID User Token, store it in keycloak user attributes via Admin API and return this token to user.
Then we create custom Authenticator SPI implementation that will extract user token from direct grant auth request and validate it.
And last step is to properly configure direct grant authentication flow for corresponding OIDC client. This flow should work like default if no user token presented in auth request and should validate only user token and ignore other credentials if user token presents.
Keycloak "server development" docs and keycloak sources are very helpful with such king of tasks.
Can I define custom scope(s) and have them returned when using the client credential flow in Azure AD?
In my experiment, I configured 2 Azure AD applications, one for a Web API and one for a client (Web API Client A). I added a scope to the Web API but when requesting the access token via the client credential flow, the scope wasn’t returned. 🤔
Also, it only allowed me to request an access token when using .default for a scope, i.e. api://web-api-client-credential-flow/.default.
I ran across this Azure Feedback item: V2.0 Client Credentials Implement Scopes so it appears scopes aren't supported in Azure AD under the client credential flow?
What’s the point in giving my Web API Client A application permissions for that scope if they are not returned? How could the Web API know if the daemon application has that scope to perform the necessary action?
It would seem I would have to use application permissions?
Yes, you have to use application permissions.
Scopes aka delegated permissions only apply when a user is involved in the login process.
They allow you to act on behalf of a user.
Application permissions are sort of roles given to the application itself.
They only apply when doing client credentials authentication, where no user is involved.
You can define application permissions on the app via the Manifest in the app registration.
These can then be assigned to the client application.
When getting the token, you must use .default because you cannot change your app permissions dynamically.
You always get what has been granted already.
In the token the permissions will be in a roles claim.
Can I define custom scope(s) and have them returned when using the client credential flow in Azure AD?
No, but you can define application permission(s) via the manifest (definitely not as nice as the UI for delegated scopes) and have them returned via the client credential flow:
Then you can provide the client app permission:
Now when requesting a token with a scope of api://web-api-client-credential-flow/.default the "scopes" are returned in the roles claim. Sample JWT
Yes, you need to use api://web-api-client-credential-flow/.default for client credential flow.
And the application permissions will be returned in roles instead of scopes.
When using Azure AD client credentials flow, should the oauth2 endpoint (of azure ad) produce a bearer token if the client application has NOT been granted permission to access the requested resource? I was certain it used to error in this case, but I'm now seeing different behavior (a valid bearer token is now provided even if the client application does NOT have permission to the resource application).
We have always allowed tokens to be issues between two services when using the client credential flow. This scenario is basically S2S between Daemon Services.
The important thing to note here is that the built in authorization model for AAD takes advantage of SCP and ROLE claims, which appear in the token and can help your API understand what permissions it has been granted by the user.
However, we want to also allow you, in this situation, to use your own authorization layer. For example, you could simply white-list the App ID of the client application to allow it to make S2S calls to your API, without the presence of any ROLE claims in the token. The token issuance behavior here enables this scenario.