OldSchool/Get-TokenByCertificate.ps1
|
Function Get-TokenByCertificate { <# .SYNOPSIS Get OAuth access token using client certificate. .EXAMPLE #Params $Certificate = Get-PfxCertificate -FilePath ./Certificate.pfx $TenantId = "12345678-1234-1234-1234-1234567890ab" $ApplicationId = "12345678-1234-1234-1234-1234567890ab" $Scope = "https://graph.microsoft.com/.default" #Token $AccessToken = Get-TokenByCertificate -Certificate $Certificate -TenantId $TenantId -ApplicationId $ApplicationId -Scope $Scope $AccessToken .NOTES Author: Michal Gajda .LINK https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#second-case-access-token-request-with-a-certificate #> [CmdletBinding()] Param ( [Parameter(Mandatory = $true)][String]$TenantId, [Parameter(Mandatory = $true)][String]$ApplicationId, [Parameter(Mandatory = $true)][System.Security.Cryptography.X509Certificates.X509Certificate2]$Certificate, [Parameter()][String]$Scope = "https://graph.microsoft.com/.default" ) #JWT params $CertificateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash()) $JWT_exp = [math]::Floor(((Get-Date) - ([datetime]::Parse("1970-01-01T00:00:00Z"))).TotalSeconds) $JWT_nbf = $JWT_exp + (10 * 60) #JWTHeader $JWTHeader = @{ alg = "RS256" typ = "JWT" x5t = "$($CertificateBase64Hash -replace '\+','-' -replace '/','_' -replace '=')" } | ConvertTo-Json -Compress #JWTClaims $JWTClaims = @{ aud = "https://login.microsoftonline.com/$TenantId/oauth2/token" exp = $JWT_exp iss = "$ApplicationId" jti = ([guid]::NewGuid()).Guid nbf = $JWT_nbf sub = "$ApplicationId" } | ConvertTo-Json -Compress $StringList = @($JWTHeader, $JWTClaims) #JWT encoding $EncodedStringList = @() $StringList | ForEach-Object { $ClearTextString = $_ # Convert supplied strings to base64 $ClearTextBytes = [System.Text.Encoding]::UTF8.GetBytes($ClearTextString) $Base64EncodedString = [System.Convert]::ToBase64String($ClearTextBytes).Replace('=', '').Replace('+', '-').Replace('/', '_') $EncodedStringList += $Base64EncodedString } # Join header and Payload with "." to create a valid (unsigned) JWT $StringToSign = $EncodedStringList -join '.' # Get the private key object of your certificate $PrivateKey = $Certificate.PrivateKey # Define RSA signature and hashing algorithm $RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1 $HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256 # Create a signature of the JWT $Signature = [System.Convert]::ToBase64String($PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($StringToSign),$HashAlgorithm,$RSAPadding)).Replace('=', '').Replace('+', '-').Replace('/', '_') # Join the signature to the JWT with "." $JWT = $StringToSign + "." + $Signature # Headers for the request with JWT as Authorization $Headers = @{ Authorization = "Bearer $JWT" } # Create a hash with body parameters $Body = @{ client_id = $ApplicationId client_assertion = $JWT client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" scope = $Scope grant_type = "client_credentials" } # Token endpoint for the request $Uri = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" # Build the token request $RequestParams = @{ ContentType = 'application/x-www-form-urlencoded' Method = 'POST' Body = $Body Uri = $Uri Headers = $Headers } # Get the token $Response = Invoke-RestMethod @RequestParams Return $Response.access_token } |