Since everything is shifting towards cloud, folks are looking more and more into possibilities and how cloud features can be incorporated into products.
One crucial topic is all around Authentication and Authorization. OAuth is the most used word in the past month,when I was approached by developers and they wanted to access somehow Exchange related data. I realized that many people having problems writing their code and usually we get blamed that we haven’t registered an application correctly in Azure AD.
Thus it’s on us to prove everything is okay and therefore I wrote a simple script for testing several scenarios in an easy way to make sure everything is configured correctly and you’re able to retrieve tokens.
What’s in scope?
The script covers the following scenarios:
- Implicit grant flow (Microsoft Docs)
- Auth code flow (Microsoft Docs)
- On-Behalf-Of flow (Microsoft Docs)
- Client Credentials (shared secret or certificate) (Microsoft Docs)
- “normal” flow
You can download the script from GitHub:
https://github.com/IngoGege/Get-AccessToken
A special thanks to fellow MVP Vasil Michev! I incorporated his function for decoding a JWT token in my script, which can be found here.
Implicit grant flow
Note: When you want to use this flow, you need to enable it by setting oauth2AllowImplicitFlow to true in the app’s manifest. If not you will get the following error:
AADSTS700051: response_type ‘token’ is not enabled for the application.
The only description I’ve found is this one for Skype for Business Web SDK.
Example:
$implicitFlow = @{
Authority = 'https://login.microsoftonline.com/'
Tenant = 'sap.com'
ClientID = '45e4d9a7-3c20-...-2fdb529aa6fc'
RedirectURI = 'https://localhost:.../'
Resource = 'https://outlook.office365.com'
UseImplicitFlow = $true
AuthPrompt = 'select_account'
Verbose = $true
}
.\Get-AccessToken.ps1 @implicitFlow
Auth code flow
In this scenario you first request an Authorization code, which is then used to request an AccessToken. You need either a ClientSecret or a Certificate, which is used as ClientAssertionCertificate, in addition.
Example:
$authCodeFlow = @{
Authority = 'https://login.microsoftonline.com/sap.com'
Tenant = 'sap.com'
ClientID = '45e4d9a7-3c20-...-2fdb529aa6fc'
ClientSecret = 'dGLulX5suo7kEJ...AGnzu7e1c0zSTEI//E='
RedirectURI = 'https://localhost:.../'
Resource = 'https://outlook.office365.com'
UseAuthCodeFlow = $true
AuthPrompt = 'select_account'
Verbose = $true
}
.\Get-AccessToken.ps1 @authCodeFlow
Verbose mode shows you also the retrieved AuthCode. Result is AccessToken and usually also the RefreshToken.
On-Behalf-Of flow
Note: This was something, where I had my problems. That’s why I’m pointing out the following settings you want to make sure there are correct:
- knownClientApplications needs to be set on the application, which consumes the previous retrieved Accesstoken. If not set the user will be asked to give consent for the service-to-service app as well. Read more about app manifest here.
- AcquireTokenAsync needed to be calling the resource of the service-to-service app, but this was during coding of the script and should not bother you.
Example:
$ClientOBO = @{
ClientID = '2eb916a1-886d-4f2c-...2db94c4b'
RedirectUri = 'https://TodoListClient-OBO'
ClearTokenCache = $true
Verbose = $true
Authority = 'https://login.microsoftonline.com/common'
Resource = 'https://your_resource.local.com/TodoListService-OBO'
ClientIDOBO = '07432964-d51b-45de-...be0b'
ResourceOBO = 'https://graph.microsoft.com'
ClientSecretOBO = 'dSYBmoFL8VdgnmboST7...mhkihA3lK+PE='
}
First retrieved AccessToken Service-to-service AccessToken
Client Credentials
Client credentials could be either a ClientSecret, which is basically a password, or a certificate, which is used as ClientAssertionCertificate when requesting an AccessToken.
Note: When no user information is used you will retrieve only an Access- and no RefreshToken.
Example:
$clientCert = @{
Authority = 'https://login.microsoftonline.com/sap.com'
ClientID = '45e4d9a7-3c20-4a51-...9aa6fc'
Resource = 'https://outlook.office365.com'
Certificate = $(dir Cert:\CurrentUser\My\ | ? thumbprint -eq BB390D788B025D72C3B9FD164961A634B19A2DB0)
RedirectURI = 'https://localhost:.../'
ClearTokenCache = $true
Verbose = $true
}
.\Get-AccessToken.ps1 @clientCert
$clientSecret = @{
Authority = 'https://login.microsoftonline.com/sap.com'
ClientID = '45e4d9a7-3c20-4a51...9aa6fc'
Resource = 'https://outlook.office365.com'
ClientSecret = 'dGLulX5suo7kEJ+x8+z...1c0zSTEI//E='
RedirectURI = 'https://localhost:.../'
ClearTokenCache = $true
Verbose = $true
}
.\Get-AccessToken.ps1 @clientSecret
Using ClientSecret Using certificate as
ClientAssertionCertificate
“normal” flow
In this flow just a ClientID and RedirectURI is used. As example I used the scenario how I use the one from EWSEditor described in my post EWS and OAuth:
$EWSEditor = @{
Authority = 'https://login.microsoftonline.com/sap.com'
ClientID = '0e4bf2e2-aa7d-46e8-aa12-263adeb3a62b'
Resource = 'https://outlook.office365.com'
RedirectURI = 'https://microsoft.com/EwsEditor'
ClearTokenCache = $true
Verbose = $true
}
.\Get-AccessToken.ps1 @EWSEditor
Common errors
The script will return the exception if something goes wrong. Here are a few I run into.
Invalid ClientSecret oauth2AllowImplicitFlow not allowed When using ADAL the Authority is validated. Depending on your flow you have to use either https://login.microsoftonline.com/{tenant}/ or https://login.microsoftonline.com/common/. There are more URIs, but those work in most cases
While using Implict or AuthCode flow and multiple identities and AuthPrompt is not set
Conclusion
The script was developed in order to validate an application registration in terms of being able to retrieve an AccessToken. Of course it can be used in other scripts (what I will do for mine), where an AccessToken is used for accessing data. The variety of scenarios should cover a lot. If you find a missing feature…it’s on GitHub.
I hope this helps with this topic and feedback is always welcome!
Pingback: OAuth: Get-AccessToken — The clueless guy – SutoCom Solutions
Pingback: Microsoft Graph, Exchange Online and the lack of proper logging | The clueless guy