PowerShell OAuth Authentication Two Ways

PowerShell OAuth Authentication Two Ways

  •  
  •  
  •  
  •  
  •  
  •  

This past week, I’ve been heads down working on an application to take inbound data from one application that doesn’t have a webhook or API available and query a Dynamics 365 instance.

In order to query Dynamics 365 (or any Azure/Microsoft 365 service, to be honest) successfully, you’ll need to work with OAuth.  We provide an application identity library (ADAL) to help with this, but it does require deploying the libraries (which, if you’re using PowerShell on another platform, may not be very useful).  Here are some code examples to get you going both ways.

Using the ADAL Libraries

First, you’re going to need to obtain the Microsoft Active Directory Authentication Library software: https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/active-directory-authentication-libraries is the place to start.  You’ll need to download, extract, and squirrel away Microsoft.IdentityModel.Clients.ActiveDirectory.dll, as it will needed to be added to the script.  You should read our terms of service to make sure you include it properly with your scripting (or trigger the application to download and install it).

Once you have the library assembly, you can use this framework to get an OAuth Access Token:

[string]$ClientId = "<guid of Azure AD app id to be used for authentication>", # Azure AD client app ID
[string]$ClientSecret = "<client secret value for corresponding app id>", # Azure AD client app secret
[string]$Tenant = "<guild>", # Azure AD tenant ID
[string]$Resource = "https://<appname.domain.com>/", # Resource realm, typically something like https://app.azurewebsites.net or https://instance.crm.dynamics.com
$AuthString = "https://login.windows.net/$($tenant)"

Add-Type -Path ".\DLL\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"

Function Create-Token
{
# Creates a context for login.windows.net (Azure AD common authentication)
[Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext]$AuthContext = [Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext]$AuthString

# Creates a credential from the client id and key
[Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential]$ClientCredential = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential"($AlientID, $ClientSecret)

# Requests a bearer token
$script:AuthenticationResult = $AuthContext.AcquireTokenAsync($Resource, $ClientCredential);
}

Call Create-Token in your application to generate an access token.  $AuthenticationResult will contain the properties that you need to construct your URL for when you use Invoke-RestMethod:

$uri = "https://appname.domain.com/api/endpoint"
$headers = @{ 'authorization' = "$($AuthenticationResult.Result.AccessTokenType) $($AuthenticationResult.Result.AccessToken) " }
$result = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers -ContentType "application/json"

$Result should store the return of your application.

Using Native REST Commands

However, it may be impractical or undesirable to distribute the ADAL libraries with your code–especially if you’re unable to download and install packages using administrative rights.  This calls for something else.  You’ll notice some similarities (I mean, in the end, you’re getting the same data).  Here’s a method that works without any specialized components:

[string]$ClientId = "<guid of Azure AD app id to be used for authentication>", # Azure AD client app ID
[string]$ClientSecret = "<client secret value for corresponding app id>", # Azure AD client app secret
[string]$Tenant = "<guild>", # Azure AD tenant ID
[string]$Resource = "https://<appname.domain.com>/", # Resource realm, typically something like https://app.azurewebsites.net or https://instance.crm.dynamics.com

Add-Type -AssemblyName System.Web

# Get Auth Token from AAD for App
Function Get-AuthToken
{
Param (
[String]$tenantId,
[String]$applicationId,
[String]$secret,
[string]$ApiEndpointUri
)
$encodedSecret = [System.Web.HttpUtility]::UrlEncode($secret)

$RequestAccessTokenUri = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$body = "grant_type=client_credentials&client_id=$applicationId&client_secret=$encodedSecret&resource=$apiEndpointUri"
$contentType = 'application/x-www-form-urlencoded'
try
{
$Token = Invoke-RestMethod -Method Post -Uri $RequestAccessTokenUri -Body $body -ContentType $contentType
$script:AuthenticationResult = Get-AuthToken -apiEndpointUri $Resource -tenantId $Tenant -applicationId $ClientId -secret $ClientSecret
}
catch { throw }
}

Similar to the ADAL method, $AuthenticationResult should store the OAuth token that you can use when sending your request to a REST endpoint.  Call Get-AuthToken to retrieve generate your token in your script or application.

Then, build your headers and your request:

$uri = "https://appname.domain.com/api/endpoint"
$headers = @{ 'authorization' = "$($authToken.token_type) $($authToken.access_token) " }
$Result = Invoke-RestMethod -Method GET -Uri $uri -Headers $headers -ContentType "application/json"

Once again, $Result will store the returned data from your request.

Up, OAuth, and away!

Published by Aaron Guilmette

Helping companies conquer inferior technology since 1997. I spend my time developing and implementing technology solutions so people can spend less time with technology. Specialties: Active Directory and Exchange consulting and deployment, Virtualization, Disaster Recovery, Office 365, datacenter migration/consolidation, cheese.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.