How to get access token from client certificate? Can we use client thumbprint directly?

honey porwal 1 Reputation point
2021-04-06T12:33:31.28+00:00

I am trying to generate access token as client credentials type client id and client certificate?
How to generate jwt token using certificate ??
Do we need to write script?

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
19,474 questions
{count} votes

4 answers

Sort by: Most helpful
  1. Siva-kumar-selvaraj 15,551 Reputation points
    2021-04-08T12:21:04.27+00:00

    Hello @honey porwal ,

    Thanks for reaching out.

    To get a token by using the client credentials grant, send a POST request to the /token Microsoft identity platform:

    First case: Access token request with a shared secret

    Second case: Access token request with a certificate

    Access token request with a certificate is a bit different from the normal Access token request with a shared secret flow (using AppId/Secret ). To get an access token using a certificate you have to:

    1. Create a Java Web Token (JWT) header.
    2. Create a JWT payload.
    3. Sign the JWT header AND payload with the previously created self-signed certificate. This will create a self made access token used for requesting a Microsoft Graph access token.
    4. Create a request body containing:
      • client_id=<application id>
      • client_assertion=<the JWT>
      • client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
      • scope=<URLEncoded scope>
      • grant_type=client_credentials

    To learn more about, read

    Here is the PowerShell script for making this happen. Alternatively, to compute the assertion, you can use one of the many JWT libraries in the language of your choice - MSAL supports this using .WithCertificate().

    $TenantName = "<your tenant name>.onmicrosoft.com"  
    $AppId = "<your application id"  
    $Certificate = Get-Item Cert:\CurrentUser\My\<self signed and uploaded cert thumbprint>  
    $Scope = "<Resource URI>" # Example: "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 = ([System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($Certificate))  
      
    # Define RSA signature and hashing algorithm  
    $RSAPadding = [Security.Cryptography.RSASignaturePadding]::Pkcs1  
    $HashAlgorithm = [Security.Cryptography.HashAlgorithmName]::SHA256  
      
      
    # 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  
    
    # View access_token  
    $Request.access_token  
    

    Hope this helps.

    -----------------------

    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.

    6 people found this answer helpful.

  2. Mohammed Shabaz 6 Reputation points
    2022-09-29T13:44:09.183+00:00

    Can we do it using c#?

    1 person found this answer helpful.
    0 comments No comments

  3. honey porwal 1 Reputation point
    2021-04-08T08:32:41.01+00:00
    0 comments No comments

  4. AchutaNukala-0750 1 Reputation point Microsoft Employee
    2023-02-01T18:45:10.45+00:00

    @Mohammed Shabaz if you want to use the c# you can go through our sample page share below

    https://learn.microsoft.com/en-us/azure/active-directory/develop/sample-v2-code

    it is also one of the samples use client secret or certificate to call the MS graph Api

    https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2/tree/master/1-Call-MSGraph

    0 comments No comments