I am trying to make a powershell batch that changes users' MFA phonenumbers using GraphAPI. I've went over some greatly helpful websites, and got to the script below. However I got stuck with the error AADSTS700027 : invalid signature and cannot fix over it. I've checked my azure portal for the Application and Certificates but they all seem to be fine.
$TenantName = "<MyTenant>.onmicrosoft.com"
$AppId = "<MyApplicationId>"
$Certificate = Get-Item Cert:\CurrentUser\My\<MyThumbprint>
$Scope = "https://graph.microsoft.com/.default"
# Create base64 hash of certificate
$CertificateBase64Hash = [System.Convert]::ToBase64String($Certificate.GetCertHash())
# Create JWT timestamp for expiration
$StartDate = (Get-Date "1970-01-01T00:00:00Z" ).ToUniversalTime()
$JWTExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End (Get-Date).ToUniversalTime().AddMinutes(2)).TotalSeconds
$JWTExpiration = [math]::Round($JWTExpirationTimeSpan,0)
# Create JWT validity start timestamp
$NotBeforeExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End ((Get-Date).ToUniversalTime())).TotalSeconds
$NotBefore = [math]::Round($NotBeforeExpirationTimeSpan,0)
# Create JWT header
$JWTHeader = @{
alg = "RS256"
typ = "JWT"
# Use the CertificateBase64Hash and replace/strip to match web encoding of base64
x5t = $CertificateBase64Hash -replace '\+','-' -replace '/','_' -replace '='
}
# Create JWT payload
$JWTPayLoad = @{
# What endpoint is allowed to use this JWT
aud = "https://login.microsoftonline.com/$TenantName/oauth2/token"
# Expiration timestamp
exp = $JWTExpiration
# Issuer = your application
iss = $AppId
# JWT ID: random guid
jti = [guid]::NewGuid()
# Not to be used before
nbf = $NotBefore
# JWT Subject
sub = $AppId
}
# Convert header and payload to base64
$JWTHeaderToByte = [System.Text.Encoding]::UTF8.GetBytes(($JWTHeader | ConvertTo-Json))
$EncodedHeader = [System.Convert]::ToBase64String($JWTHeaderToByte)
$JWTPayLoadToByte = [System.Text.Encoding]::UTF8.GetBytes(($JWTPayload | ConvertTo-Json))
$EncodedPayload = [System.Convert]::ToBase64String($JWTPayLoadToByte)
# Join header and Payload with "." to create a valid (unsigned) JWT
$JWT = $EncodedHeader + "." + $EncodedPayload
# 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]::SHA1
# Create a signature of the JWT
$Signature = [Convert]::ToBase64String(
$PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($JWT),$HashAlgorithm,$RSAPadding)
) -replace '\+','-' -replace '/','_' -replace '='
# Join the signature to the JWT with "."
$JWT = $JWT + "." + $Signature
# Create a hash with body parameters
$Body = @{
client_id = $AppId
client_assertion = $JWT
client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
scope = $Scope
grant_type = "client_credentials"
}
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Use the self-generated JWT as Authorization
$Header = @{
Authorization = "Bearer $JWT"
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
Body = $Body
Uri = $Url
Headers = $Header
}
$Request = Invoke-RestMethod @PostSplat
# Create header
$Header = @{
Authorization = "$($Request.token_type) $($Request.access_token)"
}
$Uri = "https://graph.microsoft.com/beta/users/<MyUserObjectId>/authentication/phoneMethods"
$UserMFAPhoneNumber = Invoke-RestMethod -Uri $Uri -Headers $Header -Method Get -ContentType "application/json"
Here is the actual error:
Invoke-RestMethod : {"error":"invalid_client","error_description":"AADSTS700027: Client assertion contains an invalid s
ignature. [Reason - The provided signature value did not match the expected signature value., Thumbprint of key used by
client: '<MyThumbPrint>', Found key 'Start=08/06/2020 15:23:55, End=08/06/2021 15:43:55', Pl
ease visit the Azure Portal, Graph Explorer or directly use MS Graph to see configured keys for app Id '<MyApplicationId>'. Review the documentation at https://learn.microsoft.com/en-us/graph/deployments to determine the
corresponding service endpoint and https://learn.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs
=http to build a query request URL, such as 'https://graph.microsoft.com/beta/applications/<MyApplicationId>']\r\nTrace ID: bdad204f-271a-40b0-ab3e-0bae5306c700\r\nCorrelation ID: 54edfc93-29fb-4c1b-ae12-40e79d3caa08\r\
nTimestamp: 2020-08-06 16:36:09Z","error_codes":[700027],"timestamp":"2020-08-06 16:36:09Z","trace_id":"bdad204f-271a-4
0b0-ab3e-0bae5306c700","correlation_id":"54edfc93-29fb-4c1b-ae12-40e79d3caa08","error_uri":"https://login.microsoftonli
ne.com/error?code=700027"}
What am I doing wrong? Any help is greatly appreciated. Thank you.
Because your certificate is using sha256RSA you need to use the RSACertificateExtensions so if you change the following lines in you code that should work (well it does for me)
# Get the private key object of your certificate
$PrivateKey = ([System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($Certificate))
# Define RSA signature and hashing algorithm
$RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1
$HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256