NSGetMgGraphBearer.psm1
<#
.SYNOPSIS Functions to obtain bearer tokens from Azure AD using certificates, client secrets, and managed identities. .DESCRIPTION This module provides functions to obtain bearer tokens using certificates, client secrets, and managed identities from Azure AD. It includes helper functions for modularity and ease of maintenance. #> # Helper function to get certificate Function Get-Certificate { param ( [Parameter(Mandatory = $true)] [ValidateSet('LocalMachine', 'CurrentUser')] [string]$certStore, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$thumbprint ) $cert = Get-Item -Path "Cert:\$($certStore)\My\$($thumbprint)" if (-not $cert) { throw "Certificate not found." } return $cert } # Helper function to create JWT header Function Create-JwtHeader { param ( [Parameter(Mandatory = $true)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert ) return @{ alg = "RS256" typ = "JWT" x5t = [System.Convert]::ToBase64String($cert.GetCertHash()).TrimEnd('=').Replace('+', '-').Replace('/', '_') } } # Helper function to create JWT payload Function Create-JwtPayload { param ( [Parameter(Mandatory = $true)] [string]$tenantId, [Parameter(Mandatory = $true)] [string]$applicationId ) return @{ aud = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" iss = $applicationId sub = $applicationId jti = [System.Guid]::NewGuid().ToString() nbf = [System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds() exp = ([System.DateTimeOffset]::UtcNow.AddMinutes(10)).ToUnixTimeSeconds() } } # Helper function to encode JWT Function Encode-Jwt { param ( [Parameter(Mandatory = $true)] [hashtable]$header, [Parameter(Mandatory = $true)] [hashtable]$payload ) $headerJson = $header | ConvertTo-Json -Compress $payloadJson = $payload | ConvertTo-Json -Compress $headerEncoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($headerJson)).TrimEnd('=').Replace('+', '-').Replace('/', '_') $payloadEncoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($payloadJson)).TrimEnd('=').Replace('+', '-').Replace('/', '_') return "$headerEncoded.$payloadEncoded" } # Helper function to sign JWT # Helper function to sign JWT Function Sign-Jwt { param ( [Parameter(Mandatory = $true)] [string]$token, [Parameter(Mandatory = $true)] [System.Security.Cryptography.X509Certificates.X509Certificate2]$cert ) $privateKey = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert) if (-not $privateKey) { throw "Private key not found in the certificate." } $signature = [System.Convert]::ToBase64String($privateKey.SignData([System.Text.Encoding]::UTF8.GetBytes($token), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)).TrimEnd('=').Replace('+', '-').Replace('/', '_') return "$token.$signature" } <# .SYNOPSIS Get a bearer token using a certificate. .DESCRIPTION This function obtains a bearer token from Azure AD using a certificate. It uses helper functions to get the certificate, create the JWT header and payload, encode the JWT, and sign the JWT. .PARAMETER certStore The certificate store location ('LocalMachine' or 'CurrentUser'). .PARAMETER thumbprint The thumbprint of the certificate. .PARAMETER tenantId The Azure AD tenant ID. .PARAMETER applicationId The Azure AD application ID. .PARAMETER scope The scope for the token request. Default is 'https://graph.microsoft.com/.default'. .EXAMPLE # Get a bearer token using a certificate $token = Get-CertBearerToken -certStore 'LocalMachine' -thumbprint 'YOUR_CERT_THUMBPRINT' -tenantId 'YOUR_TENANT_ID' -applicationId 'YOUR_APP_ID' Write-Output $token #> Function Get-CertBearerToken { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateSet('LocalMachine', 'CurrentUser')] [string]$certStore, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$thumbprint, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$tenantId, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$applicationId, [string]$scope = 'https://graph.microsoft.com/.default' ) try { $cert = Get-Certificate -certStore $certStore -thumbprint $thumbprint $header = Create-JwtHeader -cert $cert $payload = Create-JwtPayload -tenantId $tenantId -applicationId $applicationId $token = Encode-Jwt -header $header -payload $payload $jwt = Sign-Jwt -token $token -cert $cert $body = @{ client_id = $applicationId scope = $scope client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" client_assertion = $jwt grant_type = "client_credentials" } $response = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body $body return $response.access_token } catch { Write-Error "An error occurred: $_" } } <# .SYNOPSIS Get a bearer token using a client secret. .DESCRIPTION This function obtains a bearer token from Azure AD using a client secret. .PARAMETER tenantId The Azure AD tenant ID. .PARAMETER applicationId The Azure AD application ID. .PARAMETER clientSecret The Azure AD client secret. .EXAMPLE # Get a bearer token using a client secret $token = Get-SecretBearerToken -tenantId 'YOUR_TENANT_ID' -applicationId 'YOUR_APP_ID' -clientSecret 'YOUR_CLIENT_SECRET' Write-Output $token #> Function Get-SecretBearerToken { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$tenantId, [Parameter(Mandatory = $true)] [string]$applicationId, [Parameter(Mandatory = $true)] [string]$clientSecret ) try { $body = @{ client_id = $applicationId scope = "https://graph.microsoft.com/.default" client_secret = $clientSecret grant_type = "client_credentials" } $response = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -ContentType "application/x-www-form-urlencoded" -Body $body return $response.access_token } catch { Write-Error "An error occurred: $_" } } <# .SYNOPSIS Get a bearer token using a managed identity. .DESCRIPTION This function obtains a bearer token from Azure AD using a managed identity in an Azure Runbook. .PARAMETER resource The resource for which the token is requested. Default is 'https://graph.microsoft.com'. .EXAMPLE # Get a bearer token using a managed identity $token = Get-ManagedIdentityBearerToken -resource 'https://graph.microsoft.com' Write-Output $token #> Function Get-ManagedIdentityBearerToken { [CmdletBinding()] param ( [string]$resource = 'https://graph.microsoft.com' ) try { if ($env:IDENTITY_ENDPOINT -and $env:IDENTITY_HEADER) { $response = [System.Text.Encoding]::Default.GetString((Invoke-WebRequest -UseBasicParsing -Uri "$($env:IDENTITY_ENDPOINT)?resource=$resource" -Method 'GET' -Headers @{'X-IDENTITY-HEADER' = "$env:IDENTITY_HEADER"; 'Metadata' = 'True' }).RawContentStream.ToArray()) | ConvertFrom-Json return $response.access_token } else { $response = Invoke-RestMethod -Method Get -Uri "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=$resource" -Headers @{Metadata = "true" } return $response.access_token } } catch { Write-Error "An error occurred: $_" } } # Export only the public function Export-ModuleMember -Function Get-CertBearerToken, Get-SecretBearerToken, Get-ManagedIdentityBearerToken |