Skip to content

Instantly share code, notes, and snippets.

@doeringp
Last active December 20, 2022 10:43
Show Gist options
  • Save doeringp/20c6508cd088aaa86ffab4f7e9640380 to your computer and use it in GitHub Desktop.
Save doeringp/20c6508cd088aaa86ffab4f7e9640380 to your computer and use it in GitHub Desktop.
Get an access token from a OpenID Connect Provider with username and password or client credentials only.
<#
.SYNOPSIS
Get an access token from an OpenID Connect Provider using the passwort grant type
or the client credentials grant type (without user context).
First, you need an client id and client secret.
The Password Grant Type enables the OpenID Connect client to send a username and password directly
to the OpenID Authority to obtain an access token for the user without user interaction.
The Client Credentials Grant Type enables the client to get an access token with
his Client ID and Secret without user interaction (no user context).
IMPORTANT: This script should be used only for development and testing.
.PARAMETER OpenIdAuthority
OpenId Authority.
.PARAMETER ClientId
Client Id which must be registered before.
.PARAMETER ClientSecret
Client secret to authenticate the client.
.PARAMETER Scopes
Scopes which should be contained in the access token.
.PARAMETER User
Username to obtain an access token for.
.PARAMETER Password
Password of the user.
.PARAMETER Clip
Add the resulting Authorization header to the clipboard.
#>
Param(
[Parameter(Mandatory=$true)] [string] $OpenIdAuthority,
[Parameter(Mandatory=$true)] [string] $ClientId,
[Parameter(Mandatory=$true)] [string] $ClientSecret,
[string] $Scopes = "openid profile role",
[string] $User,
[string] $Password,
[switch] $Clip
)
$TempFolder = [System.IO.Path]::GetTempPath()
$NugetBin = "$TempFolder/nuget.exe"
$IdentityModelDll = "$TempFolder\IdentityModel.3.0.0\lib\net452\IdentityModel.dll"
$NewtonSoftJsonDll = "$TempFolder\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll"
if (-not $(Test-Path $IdentityModelDll))
{
Write-Host "Downloading IdentityModel from NuGet..."
Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile $NugetBin
. $NugetBin install IdentityModel -Version 3.0.0 -OutputDirectory $TempFolder
}
if (-not $(Test-Path $IdentityModelDll)) {
Write-Error "Unable to load IdentityModel from NuGet."
exit 1
}
Add-Type -AssemblyName System.Web
Add-Type -Path $IdentityModelDll
Add-Type -Path $NewtonSoftJsonDll
function GetAccessToken($authority, $clientId, $clientSecret, $user, $password) {
$discoClient = New-Object IdentityModel.Client.DiscoveryClient $authority
$discoClient.Policy.RequireHttps = $false
$disco = $discoClient.GetAsync().Result
# Client id and secret MUST be encoded using the "application/x-www-form-urlencoded"
# encoding algorithm to use them as username and password with HTTP Basic Authentication.
# See https://github.com/IdentityServer/IdentityServer4/issues/2086
$clientId = [System.Web.HttpUtility]::UrlEncode($clientId)
$clientSecret = [System.Web.HttpUtility]::UrlEncode($clientSecret)
$tokenClient = New-Object IdentityModel.Client.TokenClient $disco.TokenEndpoint, $clientId, $clientSecret
if ($User)
{
$tokenResponse = [IdentityModel.Client.TokenClientExtensions]::RequestResourceOwnerPasswordAsync(
$tokenClient, $User, $Password, $Scopes).Result
}
else
{
$tokenResponse = [IdentityModel.Client.TokenClientExtensions]::RequestClientCredentialsAsync(
$tokenClient, $Scopes).Result
}
if ($tokenResponse.IsError) {
Write-Error "Unable to obtain an access token from $authority. Error: $($tokenResponse.Error)"
}
return $tokenResponse.AccessToken
}
if ($User)
{
Write-Host "Acquiring an access token for client ""$ClientId"" and user ""$User"" using a password..."
}
else
{
Write-Host "Acquiring an access token for client ""$ClientId"" using client credentials..."
}
$accessToken = GetAccessToken $OpenIdAuthority $ClientId $ClientSecret $User $Password
if ($Clip)
{
Write-Host "`nAuthorization Header Value:"
Write-Host "Bearer $accessToken"
"Bearer $accessToken" | clip
Write-Host "`nThe access token has been copied to your clipboard."
}
else
{
Write-Host "Tip: You can use the option -Clip to save the Authorization header directly to the clipboard."
Write-Output $accessToken
}
@doeringp
Copy link
Author

doeringp commented Feb 14, 2022

Requesting an access token can also easily be done using CURL and the Token endpoint of your OpenID Provider directly.

Password Grant Type:

curl -X POST "https://<authority>/connect/token" `
     -H "Content-Type: application/x-www-form-urlencoded" `
     -d ("grant_type=password&" +
         "client_id=<client_id>&" +
         "client_secret=<client_secret>&" +
         "username=<username>&" +
         "password=<password>&" +
         "scope=openid profile email")

Client Credentials Grant Type:

curl -X POST "https://<authority>/connect/token" `
     -H "Content-Type: application/x-www-form-urlencoded" `
     -d ("grant_type=client_credentials&" +
         "client_id=<client_id>&" +
         "client_secret=<client_secret>&" +
         "scope=api1")

If you want to copy the access token directly to your clipboard pipe the result to:

... | wsl jq -r .access_token | clip

This only works using PowerShell, WSL (with the "jq" tool installed).

@616b2f
Copy link

616b2f commented Feb 14, 2022

thx for sharing :)

@doeringp
Copy link
Author

The way for the good old Windows PowerShell:

Invoke-RestMethod -Method 'POST' -Uri 'https://<authority>/connect/token' `
    -Headers @{"Content-Type" = "application/x-www-form-urlencoded"} `
    -Body ("grant_type=client_credentials" + 
           "&client_id=<client_id>" + 
           "&client_secret=<client_secret>" + 
           "&scope=api1")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment