generate Bearer token - active directory certificate credentials using powershell

globalAdmin1 6 Reputation points
2022-10-26T10:03:39.403+00:00

I need to generate Bearer token for graph api, that has delegated permissions by a PowerShell script. we can use clientId and certificate. or user credentials.

Microsoft Security | Microsoft Entra | Microsoft Entra ID
Microsoft Security | Microsoft Graph
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. globalAdmin1 6 Reputation points
    2022-10-27T06:54:16.85+00:00

    I found the below code to generate bearer token. Its working fine.

    $TenantName = "f7xxxxxxxxxxxxxxxxxx3f4"
    $AppId = "6xxxxxxxxxxxd"
    $Certificate = Get-Item Cert:\CurrentUser\My\xxxxxxxxxxxxxxxxxx
    $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 = ([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 = "password"
    username = "xxxxxxxxxxxxxxxxx"
    password = "xxxxxxxxxxx"

    }

    $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

    $token = $Request.access_token

    1 person found this answer helpful.

  2. CarlZhao-MSFT 46,376 Reputation points
    2022-10-27T07:17:47.227+00:00

    Hi @globalAdmin1

    Both ROPC flow and auth code flow can use certificate credentials to generate tokens with delegated permissions.

       $clientID = "client id"           
       $tenantID = "tenant id"  
       $username = "username"  
       $password = "password"  
       $client_assertion = JWT  
       $client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"  
                          
       $authUrl = "https://login.microsoftonline.com/" + $tenantID + "/oauth2/v2.0/token/"      
       $body = @{       
           "scope" = "https://graph.microsoft.com/.default";       
           "grant_type" = "password";       
           "client_id" = $clientID      
           "client_assertion_type" = $client_assertion_type   
           "client_assertion" = $client_assertion_type   
           "username" = $username  
           "password" = $password  
           }  
                  
       $authToken = Invoke-RestMethod -Uri $authUrl –Method POST -Body $body      
     Write-Output $authToken.access_token  
    

    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.
    0 comments No comments

  3. James Hamil 27,221 Reputation points Microsoft Employee Moderator
    2022-10-26T18:02:12.74+00:00

    Hi @globalAdmin1 , do you need to use the Graph API or does the base Rest API work for you? You should be able to accomplish everything with just the Rest API as detailed here. Please let me know if you've tried this or if you have any questions.

    Thank you,
    James

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.