OAuth: Get-AccessToken

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:

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

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='   
}

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

“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.

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!

2 thoughts on “OAuth: Get-AccessToken

  1. Pingback: OAuth: Get-AccessToken — The clueless guy – SutoCom Solutions

  2. Pingback: Microsoft Graph, Exchange Online and the lack of proper logging | The clueless guy

Leave a comment