git/Get-AadToken.psm1

<#
.SYNOPSIS
Get Access Token from Azure AD token endpoint.
 
.DESCRIPTION
Get Access Token from Azure AD token endpoint.
 
.PARAMETER ClientId
Provide Client ID or App ID required to get a access token
 
.PARAMETER ResourceId
Provide App URI ID or Service Principal Name you want to get an access token for.
 
.PARAMETER Scopes
Provide Scopes for the request.
 
.PARAMETER ClientSecret
Provide Client Secret if this is a Web App client.
 
.PARAMETER Redirect
Provide Redirect URI or Redirect URL.
 
.PARAMETER Username
Provide username if using Resource Owner Password grant flow.
 
.PARAMETER Password
Provide Password of resource owner if using Resource Owner Password Credential grant flow.
 
.PARAMETER Tenant
Provide Tenant ID you are authenticating to.
 
.PARAMETER Instance
Provide Azure AD Instance you are connecting to.
 
.PARAMETER UseV2
By default, Azure AD V1 authentication endpoints will be used. Use this if you want to use the V2 Authentication endpoints.
 
.PARAMETER UseResourceOwner
Enable this switch if you want to use the Resource Owner Password Credential grant flow.
 
.PARAMETER UseClientCredential
Enable this switch if you want to use the Client Credential grant flow.
 
.PARAMETER UseRefreshToken
Enable this switch if you want to use the Refresh Token grant flow.
 
.EXAMPLE
Use Resource Owner Password Credential grant flow
Get-AadToken -UseResourceOwner -ResourceId "https://graph.microsoft.com" -ClientId 5567ba8a-e608-4219-97d8-3d3ea63718e7 -Redirect "https://login.microsoftonline.com/common/oauth2/nativeclient" -Username john@contoso.com -Password P@$$w0rd!
 
To get client only access token
Get-AadToken -UseClientCredential -ResourceId "https://graph.microsoft.com" -ClientId 5567ba8a-e608-4219-97d8-3d3ea63718e7 -ClientSecret "98iwjdc-098343js="
 
.NOTES
General notes
#>


function Get-AadToken
{
    [CmdletBinding(DefaultParameterSetName="All")] 
    param(
        [Parameter(Mandatory=$true)]
        $ClientId,

        [Parameter(ParameterSetName="UseResourceOwner", Mandatory=$false)]
        [switch]
        $UseResourceOwner,

        [Parameter(ParameterSetName="UseClientCredential", Mandatory=$false)]
        [switch]
        $UseClientCredential,

        [Parameter(ParameterSetName="UseRefreshToken", Mandatory=$false)]
        [switch]
        $UseRefreshToken,   

        [Parameter(ParameterSetName="UseResourceOwner", Mandatory=$true)]
        $Username = $null,

        [Parameter(ParameterSetName="UseResourceOwner", Mandatory=$true)]
        $Password = $null,

        [Parameter(ParameterSetName="UseClientCredential", Mandatory=$true)]
        [Parameter(ParameterSetName="UseRefreshToken", Mandatory=$false)]
        [Parameter(ParameterSetName="UseResourceOwner", Mandatory=$false)]
        $ClientSecret = $null,

        [Parameter(ParameterSetName="UseRefreshToken", Mandatory=$true)]
        $RefreshToken,
        
        [Parameter(ParameterSetName="UseClientCredential", Mandatory=$true)]
        [Parameter(ParameterSetName="UseRefreshToken", Mandatory=$false)]
        [Parameter(ParameterSetName="UseResourceOwner", Mandatory=$false)]
        $Tenant,

        $ResourceId = "https://graph.microsoft.com",
        $Scopes = "openid email profile offline_access https://graph.microsoft.com/.default",
        $Redirect = $null,
        $Instance = "https://login.microsoftonline.com",

        [switch]
        $UseV2 = $false
    )

    $error.Clear()
    $scriptError = $null
    
    # Set Grant_Type
    if (-not $UseResourceOwner -and -not $UseClientCredential -and -not $UseRefreshToken)
    {
        do {
            $isValidChoice = $true
            Write-Host ""
            Write-Host "Do you want to..." -ForegroundColor Yellow
            Write-Host "1: Resource Owner (Provice user name and password)"
            Write-Host "2: Client Credential (Provice Client ID and Client Secret)"
            Write-Host "3: Refresh (Provide Refresh Token)"
            Write-Host "Type 'exit' to quit."
            Write-Host ""
            $choice = Read-Host -Prompt "Enter your choice (#)"
            Write-Host ""
            switch ($choice) 
            {
                "1" 
                {
                    $UseResourceOwner = $true 
                    break
                }

                "2" 
                {
                    $UseClientCredential = $true 
                    break
                }

                "3" 
                {
                    $UseRefreshToken = $true
                    break
                }

                "exit" {return}

                "default" 
                {
                    $isValidChoice = $false; 
                    break
                }
            }
        } while (-not $isValidChoice)
    }

    if ($UseResourceOwner)
    {
        $GrantType = "password"
    }

    if ($UseClientCredential)
    {
        
    }

    if ($UseRefreshToken)
    {
        $GrantType = "refresh_token"
    }


    # Requirements for ClientCredentials
    if($UseClientCredential)
    {
        $GrantType = "client_credentials"

        if (-not $Tenant)
        {
            $Tenant = Read-Host -Prompt "Tenant"
        }

        if (-not $ClientSecret)
        {
            $ClientSecret = Read-Host -Prompt "ClientSecret"
        }
    }


    # Requirements for Resource Owner
    if($UseResourceOwner)
    {
        $GrantType = "password"
        
        if (-not $Username)
        {
            $Username = Read-Host -Prompt "Username"
        }

        if (-not $Password)
        {
            $Password = Read-Host -AsSecureString -Prompt "Password"
        }
    }


    # Requirements for Refresh Token
    if($UseRefreshToken)
    {
        $GrantType = "refresh_token"
        if (-not $RefreshToken)
        {
            $RefreshToken = Read-Host -Prompt "Refresh Token"
        }
    }


    # Set default Tenant
    if (-not $Tenant)
    {
        $Tenant = "common"
    }


    # Start initializing the Token result object
    $token = @{}

    # Start initializing the token endpoint POST content
    $body            = @{}

    # Set up if AAD V1 or V2 authentication is used...
    if ($UseV2) {
        # Use V2 endpoint
        $authUrl = "$Instance/$Tenant/oauth2/v2.0/token"
    }

    else {
        # Use V1 endpoint
        $authUrl = "$Instance/$Tenant/oauth2/token"
        $body.resource = "$ResourceId"
    }

    $token.authUrl = $authUrl

    $body.client_id  = $ClientID
    $body.grant_type = $GrantType
    $body.scope      = $scopes
    $body.nonce      = 1234
    $body.state      = 5678

    if ($Redirect)
    {
        $body.redirect_uri = $Redirect
    }

    if ($RefreshToken)
    {
        $body.refresh_token = $RefreshToken
    }

    if ($ClientSecret) {
        $body.client_secret = $ClientSecret
    }

    if ($Username -and $Password) {
        $body.username   = $Username
        $body.password   = $Password
        $body.grant_type = "password"
    }

    $token.PostContent = $body

    # Sign-in to Azure AD & Get Access Token
    try {
        Write-Verbose "Authenticating to '$authUrl'"
        
        $response = $null
        $response      = Invoke-WebRequest -Method Post -Uri $authUrl -Body $body -verbose

        $content = $null

        if($response.content) {
            $content = $response.content | ConvertFrom-Json
        }
        elseif($response.access_token) {
            $content = $response
        }

        if ($content.access_token)   { $token.AccessToken = $content.access_token }
        if ($content.id_token)       { $token.IdToken = $content.id_token }
        if ($content.refresh_token)  { $token.RefreshToken = $content.refresh_token }
        if ($content.Type)           { $token.Type = $content.Type }
        if ($content.scope)          { $token.scope = $content.scope }
        if ($content.expires_in)     { $token.expires_in = $content.expires_in }
        if ($content.ext_expires_in) { $token.ext_expires_in = $content.ext_expires_in }
        if ($content.expires_on)     { $token.expires_on = $content.expires_on }
        if ($content.not_before)     { $token.not_before = $content.not_before }
        if ($content.resource)       { $token.resource = $content.resource }

        if($IdToken) {
            Write-Verbose ""
            Write-Verbose "++++++++++++++++++++++++++++"
            Write-Verbose "ID Token"
            Write-Verbose ""
            Write-Verbose $IdToken
            Write-Verbose ""
        }

        if($AccessToken) {
            Write-Verbose ""
            Write-Verbose "++++++++++++++++++++++++++++"
            Write-Verbose "Access Token"
            Write-Verbose ""
            Write-Verbose $AccessToken
            Write-Verbose ""
        }
    }

    # Acquire token failed
    Catch {
        
        $scriptError = $_
        $scriptError = $scriptError | ConvertFrom-Json

        $token.Error = $scriptError

        # AADSTS65001
        if ($scriptError -match "AADSTS65001") {
            $consentUrl = "$Instance/$Tenant/oauth2/authorize?client_id=$ClientId&response_type=code&redirect=$RedirectUri&prompt=admin_consent"
            Write-Host ""
            Write-Host "Consent Required" -ForegroundColor Yellow
            Write-Host ""
            Write-Host "Go to the following url '$consentUrl'" -ForegroundColor Yellow
        }

        # AADSTS50079
        if ($scriptError -match "AADSTS50079") {

            $claims = $scriptError.claims | ConvertFrom-Json
            $capolids = $claims.access_token.capolids.values

            Write-Host ""
            Write-Host "User Interaction Required due to Conditional Access Policy Id '$capolids'" -ForegroundColor Yellow

        }

        return $token
    }

    $Headers = @{ "Authorization" = "Bearer $AccessToken" }
    $token.Headers = $Headers
    $token.AccessTokenClaims = $token.AccessToken | ConvertFrom-AadJwtToken
    $token.IdTokenClaims = $token.IdToken | ConvertFrom-AadJwtToken

    $Object = New-Object PSObject -Property $token

    return $Object
}






# ##############################################################################################
# CLIENT ASSERTION
# ##############################################################################################
function ClientAssertion 
{
    param($ClientId, $ClientSecret, $ClientAssertion)

    $body            = @{}
    $body.client_id  = $ClientId
    $body.client_secret  = $ClientSecret
    $body.refresh_token  = [System.Web.HttpUtility]::UrlEncode($RefreshToken)
    $body.grant_type = "refresh_token"

    try {
        Write-Host "Authenticating to '$authUrl'" -ForegroundColor Yellow
        $body | ft
        
        $response = $null
        $response      = Invoke-WebRequest -Method Post -Uri $authUrl -Body $body -verbose
    
        $content = $null
    
        if($response.content) {
            $content = $response.content | ConvertFrom-Json
        }
        elseif($response.access_token) {
            $content = $response
        }
        
        $AccessToken = $null
        $AccessToken = $content.access_token
    
        if($AccessToken) {
            Write-Host "Acquired Access Token successfull!"
        }
    }

    Catch {
        $scriptError = $_
    
        if ($response) {
            $scriptError = $scriptError | ConvertFrom-Json
            $scriptError
        } 
        else {
                throw $scriptError
        }
    }
}