
Access Token verkrijgen onder de knie: Client Credentials Flow
Hoe de client credential flow te gebruiken bij het verkrijgen van een access token
Dit blogbericht maakt deel uit van een reeks. In dit bericht belichten we het gebruik van een certificaat. Bekijk de andere berichten over de andere autorisatiestromen:
Access Token verkrijgen onder de knie: De authorization code flow
Access Token verkrijgen onder de knie: Een refresh token gebruiken
Access Token verkrijgen onder de knie: Client Credentials Flow
Hoewel het gebruik van de client credentials flow met een client secret een van mijn favoriete manieren is om een access token te verkrijgen, is het gebruik van een certificaat een van de veiligste. Dit is hetzelfde als het gebruik van een client secret, maar dan geef je client_assertion en client_assertion_type op in de body van het verzoek in plaats van client_secret.
Terwijl de parameter client_assertion_type altijd dezelfde waarde heeft, draait deze vorm van authenticatie om de parameter client_assertion. Dit is een JWT (JSON Web Token) dat bestaat uit de volgende drie delen, gescheiden door een punt:
De beveiliging in deze authenticatievorm is het feit dat je in de payload kunt aangeven hoe lang en tot wanneer precies de JWT geldig mag blijven. En het feit dat de handtekening digitaal is ondertekend met de privésleutel van je certificaat. Zo kan de App-registratie op authenticiteit controleren voordat een access token wordt verleend, omdat ditzelfde certificaat is geconfigureerd in de Entra App-registratie.
Om een access token te verkrijgen met deze autorisatiestroom moeten we 3 dingen doen:
Laten we eerst het certificaat aanmaken. We kunnen dit doen met PowerShell. Dit certificaat wordt toegevoegd aan de certificatenlocatie van de computer. Daarna exporteren we het zodat we het kunnen uploaden in onze Entra App-registratie. Met dit stukje PowerShell-code kunnen we het certificaat aanmaken en exporteren. Let op: ik gebruik de C:-locatie om mijn certificaat naar te exporteren, maar je kunt een locatie naar keuze kiezen.
$certname = "MySyperAwesomeCertificate"
$cert = New-SelfSignedCertificate -Subject "CN=$certname" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256
Export-Certificate -Cert $cert -FilePath "C:\$certname.cer"
Als alles goed gaat, zie je zoiets als dit:

Nu we ons certificaat hebben, kunnen we het uploaden naar onze Entra App-registratie in de sectie Certificates & secrets:

Vervolgens schuift er een paneel aan de rechterkant open. Selecteer je certificaat van de locatie waar je het naartoe hebt geëxporteerd en geef je certificaat een beschrijving (optioneel).

Voor het verkrijgen van een JWT op basis van je certificaat gebruik ik onderstaand PowerShell-script. In dit script moet je 3 parameters opgeven:
![]()
Twee secties die ik wil uitlichten zijn de header en de payload. Dit zijn 2 objecten die uiteindelijk worden gecodeerd naar een base64-tekenreeks. De header bestaat uit de volgende parameters:
De payload bestaat uit de volgende parameters:
aud: (doelgroep) identificeert de ontvangers waarvoor de JWT bedoeld is. In dit geval is dit https://login.microsoft.com/[YOUR_TENANT_ID]/oauth2/v2.0/token.
exp: (vervaltijd) dit geeft aan wanneer de JWT moet verlopen. Dit zorgt ervoor dat de JWT niet onbeperkt geldig is, maar slechts voor een bepaalde periode. Het onderstaande codefragment gebruikt 5 minuten.
iss: (uitgever) Het geeft aan wie de JWT heeft uitgegeven, d.w.z. de entiteit die verantwoordelijk is voor het aanmaken en ondertekenen van het token. In dit geval de client-ID.
jwt: (JWT-ID) Een unieke identifier (GUID) voor het token.
nbf: (Not Before) De tijd vanaf wanneer het token geldig is.
sub: (onderwerp) Het onderwerp van het token, bijvoorbeeld de entiteit waarop het token van toepassing is. Moet hetzelfde zijn als iss, dus je client-ID.
iat: (uitgegeven op) De tijd waarop het token is uitgegeven.
$TenantId = "[YOUR_TENANT_ID]"
$ClientId = "[YOUR_CLIENT_ID]"
# Load the self-signed and uploaded certificate using its thumbprint
$Certificate = Get-Item Cert:\CurrentUser\My\[YOUR_THUMBPRINT]
# Convert the certificate to a base64 string hash of the certificate
$CertificateAsBase64 = [System.Convert]::ToBase64String($Certificate.GetCertHash())
# Create a start date for creating a timespan
$StartDate = (Get-Date "1970-01-01T00:00:00Z").ToUniversalTime()
#Make a timespan from StartDate and let it expire after 5 minutes
$ExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End (Get-Date).ToUniversalTime().AddMinutes(5)).TotalSeconds
$Expiration = [math]::Round($ExpirationTimeSpan, 0)
# Create a timespan before which the JWT MUST NOT be accepted for processing
$NotBeforeExpirationTimeSpan = (New-TimeSpan -Start $StartDate -End ((Get-Date).ToUniversalTime())).TotalSeconds
$Nbf = [math]::Round($NotBeforeExpirationTimeSpan, 0)
# Create the header
$Header = @{
alg = "RS256"
typ = "JWT"
x5t = $CertificateAsBase64 -replace '\+', '-' -replace '/', '_' -replace '='
}
# Create the payload
$Payload = @{
aud = "https://login.microsoftonline.com/$TenantId/oauth2/token"
exp = $Expiration
iss = $ClientId
jti = [guid]::NewGuid()
nbf = $Nbf
sub = $ClientId
}
# Convert header to base64
$HeaderAsBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($Header | ConvertTo-Json)))
# Convert header to base64
$PayloadAsBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($Payload | ConvertTo-Json)))
# Combine header and payload with "." to form an unsigned JWT
$UnsignedJWT = $HeaderAsBase64 + "." + $PayloadAsBase64
# Retrieve the private key object from the certificate
$PrivateKey = ([System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($Certificate))
# Create a RSA Signature padding
$RSASignaturePadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1
# Create a hashalgoritm
$HashAlgorithmName = [Security.Cryptography.HashAlgorithmName]::SHA256
# Create the JWT signature
$JWTSignature = [Convert]::ToBase64String($PrivateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($UnsignedJWT), $HashAlgorithmName, $RSASignaturePadding)) -replace '\+', '-' -replace '/', '_' -replace '='
# Combine the signature with the JWT using "."
$SignedJWT = $UnsignedJWT + "." + $JWTSignature
Om het access token op te halen moeten we een POST-verzoek doen naar het endpoint https://login.microsoft.com/[YOUR_TENANT_ID]/oauth2/v2.0/token met de volgende parameters in de body van het verzoek:
$SignedJWT)https://graph.microsoft.com/.default zijn.
Als alles goed gaat, zou je een reactie als deze moeten ontvangen:
