Skip to content

alflokken/PSAuthClient

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PSAuthClient

PSAuthClient is a flexible PowerShell OAuth2.0/OpenID Connect (OIDC) Client.


Auth client in use

Table of Contents

Install

Either install the module from PSGallery Install-Module PSAuthClient -Scope:CurrentUser or download and unzip to ‘$home\Documents\WindowsPowerShell\Modules’.

Quick Start

Check out my blog post on getting started with PSAuthClient.

Documentation

See links for function documentation, usage and examples.

Function Description
Invoke-OAuth2AuthorizationEndpoint Launches an embedded WebView2 browser to perform the OAuth2.0/OIDC Authorization Code flow. Supports modern authentication features (SSO, Windows Hello, FIDO2).
Invoke-OAuth2DeviceAuthorizationEndpoint Initiates the Device Code flow by retrieving a user and device verification code from the authorization server that can be used to request tokens from the token endpoint.
Invoke-OAuth2TokenEndpoint Requests security tokens using various grant types: authorization code, device code, refresh token, client credentials, or JWT assertions.
Get-OidcConfigurationMetadata Retrieves OpenID Connect Discovery metadata (.well-known/openid-configuration).
ConvertFrom-JsonWebToken Decodes a JWT and returns a PowerShell object.
Test-JsonWebTokenSignature Attempts to verify the JWT signature using the issuer’s published signing keys (via discovery metadata) or provided certificate/secret.
New-PkceChallenge Generates a PKCE code_verifier and code_challenge pair for Authorization Code flows.
New-Oauth2JwtAssertion Builds and signs a JWT assertion using either a client certificate or HMAC secret, suitable for private_key_jwt or client_secret_jwt authentication methods.
Clear-WebView2Cache Deletes the WebView2 User Data Folder to clear cached sessions and cookies.

Example usage of additional tools

OIDC Discovery

Retrieve OpenID Connect Discovery metadata.

Get-OidcDiscoveryMetadata "https://login.microsoftonline.com/common"

token_endpoint                        : https://login.microsoftonline.com/common/oauth2/token
token_endpoint_auth_methods_supported : {client_secret_post, private_key_jwt, client_secret_basic}
jwks_uri                              : https://login.microsoftonline.com/common/discovery/keys
response_modes_supported              : {query, fragment, form_post}
subject_types_supported               : {pairwise}
id_token_signing_alg_values_supported : {RS256}
response_types_supported              : {code, id_token, code id_token, token id_token}
scopes_supported                      : {openid}
issuer                                : https://sts.windows.net/{tenantid}/
microsoft_multi_refresh_token         : True
authorization_endpoint                : https://login.microsoftonline.com/common/oauth2/authorize
device_authorization_endpoint         : https://login.microsoftonline.com/common/oauth2/devicecode
http_logout_supported                 : True
frontchannel_logout_supported         : True
end_session_endpoint                  : https://login.microsoftonline.com/common/oauth2/logout
claims_supported                      : {sub, iss, cloud_instance_name, cloud_instance_host_name}
check_session_iframe                  : https://login.microsoftonline.com/common/oauth2/checksession
userinfo_endpoint                     : https://login.microsoftonline.com/common/openid/userinfo
kerberos_endpoint                     : https://login.microsoftonline.com/common/kerberos
tenant_region_scope                   : 
cloud_instance_name                   : microsoftonline.com
cloud_graph_host_name                 : graph.windows.net
msgraph_host                          : graph.microsoft.com
rbac_url                              : https://pas.windows.net

Decode JWT

Convert (decode) a JSON Web Token (JWT) to a PowerShell object.

PS> ConvertFrom-JsonWebToken "ew0KICAidHlwIjogIkpXVCIsDQogICJhbGciOiAiUlMyNTYiDQp9.ew0KICAi..."

header    : @{typ=JWT; alg=RS256}
exp       : 1706784929
echo      : Hello World!
nbf       : 1706784629
sub       : PSAuthClient
iss       : https://example.org
jti       : 27913c80-40d1-46a3-89d5-d3fb9f0d1e4e
iat       : 1706784629
aud       : PSAuthClient
signature : OHIxRGxuaXVLTjh4eXhRZ0VWYmZ3SHNlQ29iOUFBUVRMK1dqWUpWMEVXMD0


Validate JWT Signature

Attempt to validate the signature of a JSON Web Token (JWT) by using the issuer discovery metadata to get the signing certificate. (If no signing certificate or secret was provided.)

PS> Test-JsonWebTokenSignature -jwtInput $jwt
True
Build JWT Assertions

Create and sign JWT Assertions using either a client_certificate (x509certificate2 or RSA Private key) or client_secret (for HMAC-based signature).

PS> New-Oauth2JwtAssertion -issuer "test" -subject "test1" -audience "test2" -jwtId "123" -customClaims @{ claim1 = "test" } -client_secret "secret"

client_assertion_jwt           ew0KICAiYWxnIjogIlJTMjU2IiwNCiAgInR5cCI6ICJKV1QiDQp9.ew0KICAianRp...
client_assertion_type          urn:ietf:params:oauth:client-assertion-type:jwt-bearer
header                         @{alg=RS256; typ=JWT}
payload                        @{jti=123; claim1=test; aud=test2; exp=1706793151; nbf=170679285...}
Generate a PKCE Challenge

Generate code_verifier and code_challenge for PKCE (authorization code flow).

PS> New-PkceChallenge

code_verifier                  Vpq2YXOsD~1DRM-jBPR6bt8R-3dWQAHNLVLUIDxh7SkWpOT3A0grpenqKne5rAHcVKsTi-ya8-lGBxJ0NS7zavdcFbfdN0yFQ5kYOFbWBh3
code_challenge                 TW-3r-6mxRWjhkkxmYOabLlwIQ0JkQ0ndxzOSLJvCoU
code_challenge_method          S256

Examples of different OpenID Connect (OIDC) and OAuth2.0 Grants

OpenID Connect is an extension of OAuth2 that adds an identity layer to the authorization framework. This allows a client to verify the identity of the user and obtain basic profile information. OIDC grants contains 'openid' scope and the identity provider will return a 'id_token' with user information (claims).

Parameters that are used (and modified) throughout the examples below.
$authorization_endpoint = "https://login.microsoftonline.com/example.org/oauth2/v2.0/authorize"
$token_endpoint = "https://login.microsoftonline.com/example.org/oauth2/v2.0/token"

$splat = @{
    client_id = "5eda97cf-2963-41e9-bea0-b6ba2bbf8f99"
    scope = "user.read openid offline_access"
    redirect_uri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
    customParameters = @{ 
        prompt = "none"
    }
}


Authorization Code Grant with Proof Key for Code Exchange (PKCE)

Example

$code = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint @splat

client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
code_verifier                  ig0Sly4Kdjc_e77Zsp5..PKi.TbqzSNz_CEKsamyPRI5~uRr4_
nonce                          o180HoFS2k5y0gj.spbYos.IPUS8-SqSf4cx0Z7x
redirect_uri                   https://login.microsoftonline.com/common/oauth2/nativeclient
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAIAAAA...

$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @code

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 5340
ext_expires_in  : 5340
access_token    : eyJ0eXAiOiJKV1QiLCJub25jZSI6IlhFMjJvBXRyVDBkQ1Z1cG7zbEFJQk1kU1RxLS5xQUppS3Fpbr...
refresh_token   : 0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAEAAAAmoFfGtYxvRrNr...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndpaU5ZT2hIYm...
expiry_datetime : 31.01.2024 14:11:08

Authorization Code Grant

Example

$code = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint @splat -usePkce:$false

nonce                          UYhqAG~GLvZqGj4hnlTkYFJY9LVcS9TrWiq.8n8Vu
redirect_uri                   https://login.microsoftonline.com/common/oauth2/nativeclient
client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAmoFfG...

$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @code

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 3848
ext_expires_in  : 3848
access_token    : eyJ0eXAiOiJKV1QiLCJub62jZSI6ImhDRkwxMjVHdE85SmNqS0NWMFZQLWxTd2Z0Zm12LXFsV2VDR0...
refresh_token   : 0.AUcAjvFfm8BTokWLwpwMkJCyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAEAAAAmoFfGtYxjHyNf...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndpaU547ZT2hI...
expiry_datetime : 31.01.2024 14:05:18
Authorization Code Grant with Client Authentication (secret)

Example

$splat.redirect_uri = "https://localhost/web"
$code = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint @splat 

client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
code_verifier                  jWe-ecfnqZ.weAxbb-qHiZ3oe7LZ-tEyWq~7UB9RcNfZn65Xq2zPO7-8rv-5tp24p...
nonce                          HRBD6BuH9PQM2_Kmuqj6KTranVVcuL80fsEpll-9nppaZp0H3CQaYhaqQ2VqUV8
redirect_uri                   https://localhost/web
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAIAAAm...

$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @code -client_secret $client_secret

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 4069
ext_expires_in  : 4069
access_token    : eyJ0eXAiOiJKG1QqLCJub25jZSI5IllOTzdpTmdXZnMtSmSSY1hpZk45bTdoa2E0WnNpWFY5ckswen...
refresh_token   : 0.AUcAjvFfmC9TokWLwpwMj2CyxiGBP5hz2ZpRrJuc3chlhOUGAVw.AgABAAEAAAAmoFfGtYxvRrNf...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndpaU5ZT2hIYm...
expiry_datetime : 31.01.2024 14:28:58
Refresh Token Grant

Example

$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint -refresh_token $token.refresh_token -client_id $splat.client_id -scope $splat.scope -nonce $code.nonce

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 3951
ext_expires_in  : 3951
access_token    : eyJ0eXAiOiJKR1QiLCJsf52jZSI6IjdCbkI2VDc5OGJZVlh3ZHdIRWVOMGducUVKQVBEUnBPcTZhMm...
refresh_token   : 0.AUcAjvFfm1BTokWLkjrMj3CyxiGBP5hz4ZpErJuc3chlhOUNAVw.AgABAAEAAAAmoFfGtDxvRrNa...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndsapaU5ZT2hI...
expiry_datetime : 31.01.2024 14:16:56
Client Credentials Grant (client_secret_basic)

Example

$splat.Remove("customParameters")
$splat.scope = ".default"
$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @splat -client_secret (Invoke-Cache -keyName "PSC_Test-ClientSecret") -client_auth_method client_secret_basic

token_type      : Bearer
expires_in      : 3599
ext_expires_in  : 3599
access_token    : eyJ0eXAiOiJKV1DiLCJub25jZSI3IjUtQjB0bXBSNHhzYWtJSW8wOFY5ejFGVGRTWDF5blZfalNVX2...
expiry_datetime : 31.01.2024 14:14:06
Client Credentials Grant (client_secret_post)
$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @splat -client_secret (Invoke-Cache -keyName "PSC_Test-ClientSecret" -asSecureString)

token_type      : Bearer
expires_in      : 3599
ext_expires_in  : 3599
access_token    : eyJ0eXAiOiJKV1QiGCJub25jZSI3ImtIeW5MWTNyUjdja0lZd1RTQWVSRi1yRnVYYUx0Y6VaU11NEF...
expiry_datetime : 31.01.2024 14:16:10
Client Credentials Grant (client_secret_jwt)

Example

# Microsoft Graph DOES NOT support client_secret_jwt, but if they did, this is how you would do it.
$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @splat -client_secret $client_secret -client_auth_method "client_secret_jwt"

error          error_description
-----          -----------------
invalid_client AADSTS5002723: Invalid JWT token. No certificate SHA-1 thumbprint, certificate SH...
Client Credentials Grant certificate (private_key_jwt)

Example

$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @splat -client_certificate "Cert:\CurrentUser\My\8ade399dddc5973e04e34ac19fe8f8759ba059b8"

token_type      : Bearer
expires_in      : 3599
ext_expires_in  : 3599
access_token    : eyJ0eXAiOiJKV1QiLCJub21jZSI2InpBUjQ6UTBRc7dzYkcxOVJibQ032s2UUxrckZUcm9BYmwgdh0...
expiry_datetime : 31.01.2024 14:20:03
Implicit Grant (OAuth2.0)

Example

$splat.redirect_uri = "https://localhost/spa"
$splat.scope = "User.Read"
$token = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint @splat -response_type "token" -usePkce:$false

expires_in                     4371
expiry_datetime                31.01.2024 14:39:19
scope                          User.Read profile openid email
session_state                  5c044a56-543e-4bcc-a94f-d411ddec5a87
access_token                   eyJ0eXAiOiJKV1QiLCJkj76jZSI6InlaZzBmU1NGV1M1UmllaFRHc01jMWJkSFNIZ...
token_type                     Bearer
Implicit Grant (OIDC)

Example

$token = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint @splat -response_type "token id_token" -usePkce:$false

nonce                          NtKwrnSuV7xQQiya.jNXF940RQkS0OMlTcQDCOOgJay8a2qi0.MO4KKX8xc-XWUa
expires_in                     4949
id_token                       eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQ...
expiry_datetime                31.01.2024 14:46:35
scope                          User.Read profile openid email
session_state                  5c044a56-543e-4bcc-a94f-d411ddec5a87
access_token                   eyJ0eXAiOiJKV1QiLCJub51jZSI6Ik2saWhWbkdCMzNYUnI0VTF5VUVYLXA0Zkp6K...
token_type                     Bearer
Hybrid Grant

Example

$splat.scope = "user.read openid offline_access"
$splat.redirect_uri = "http://localhost"
$splat.usePkce = $true
$token = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint  @splat -response_type "code id_token"

nonce                          7B61P-.ST87WdKZ9TPF~1a5sMkPs.atxj8sBCmY2mHHfEKRotmK37dxDl
code_verifier                  w6Fvr5LTkex0k.aRJhL9rZeEDNSO5sdc8zeQYlstYJuZ2K9ck2azZ~Luxeaw2CCSd...
id_token                       eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQ...
client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
session_state                  5c044a56-543e-4bcc-a94f-d411ddec5a87
redirect_uri                   http://localhost
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAAAAmo...

$token.Remove("id_token"); $token.Remove("session_state")
$tokens = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @token

nonce                          da1EE3-RRVJO.fFeCEw2TvG7hK46AWFWHJCOBeRfnJ6o
code_verifier                  ~4fYq2QcXlSIZN_vZ7pnKsO5VZ0Pq39hsdQOAziqDqsGNL-JGP~
client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
redirect_uri                   http://localhost
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAIAAAA...
Implicit Flow (by Form_Post)

Example

$splat.redirect_uri = "http://localhost:5001/"
$customParameters = @{ 
    prompt = "none" # login, none, consent, select_account
}
$token = Invoke-OAuth2AuthorizationEndpoint -uri $authorization_endpoint  @splat -response_type "code id_token" -response_mode "form_post"

nonce                          iOJ6n7jBlYAL_TrYlFjfKwOsPklX1-4iR
code_verifier                  j1v4ZEjF4AE.lMfsQ36UzF6OoBp.zwuJ7Qkez9XQX~4lGo9pnxxtN.P4ulFhkwBaZ...
id_token                       eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQ...
client_id                      5eda97cf-2963-41e9-bea0-b6ba2bbf8f99
session_state                  5c044a56-543e-4bcc-a94f-d411ddec5a87
redirect_uri                   http://localhost:5001/
code                           0.AUcAjvFfm8BTokWLwpwMj2CyxiGBP5hz2ZpErJuc3chlhOUNAVw.AgABAAIAmoF...


$token.Remove("id_token"); $token.Remove("session_state")
$tokens = Invoke-OAuth2TokenEndpoint -uri $token_endpoint @token

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 4840
ext_expires_in  : 4840
access_token    : eyJ0eXAiOiJKV1QiLCJub55jZSI6IlRsTFVNS5MyaEpscDNfNzKH75GXMXI0WndKMnlKJSJzFdzJEb...
refresh_token   : 0.AUcAjvFfm8BTokSLwpwMj2CyxiGBP5kH76pErJuc3chlhOUNAVw.AgABAAEAPKIZ-AgDs_wSA9P9...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndpaU5ZT2hIYm...
expiry_datetime : 31.01.2024 14:54:54
Device Code Grant

Example

$deviceCode = Invoke-OAuth2DeviceAuthorizationEndpoint -uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/devicecode" -client_id $splat.client_id -scope $splat.scope

user_code        : L8EFTXRY3
device_code      : LAQABAAEAAAAmoFfGtYxvRrNriQdPKIZ-2b64dTFbGcmRF3rSBagHQGtBcyz0K_XV8ltq-nXz8Ks6...
verification_uri : https://microsoft.com/devicelogin
expires_in       : 900
interval         : 5
message          : To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the co...

# Pop interactive browser
Invoke-WebView2 -uri "https://microsoft.com/devicelogin" -UrlCloseConditionRegex "//appverify$" -title "Device Code Flow" | Out-Null

# After user-interaction has been completed.
$token = Invoke-OAuth2TokenEndpoint -uri $token_endpoint -device_code $deviceCode.device_code -client_id $splat.client_id

token_type      : Bearer
scope           : User.Read profile openid email
expires_in      : 5320
ext_expires_in  : 5320
access_token    : eyJ0eXAiOiJKV1QiKH6Gb25jZSI5IjlzanppVWtNSlkR4WxfWjBRWFJRZUl4TEdyaDBad05TQ01sQ1...
refresh_token   : 0.AUcAjvFfm8BlORWLwpwMj2CyxiGBP5hz2ZpErkU62chlhOUNAVw.AgABAAEAAAAmoFfGtYxvRrlK...
id_token        : eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtXYmthYTZxczh3c1RuQndpaU5ZT2hIYm...
expiry_datetime : 31.01.2024 15:07:19

Resource Owner Password Flow (ROPC) I did not bother to implement this flow, as its insecure and not recommended for use. Its fairly trivial to implement if you need it. See https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth-ropc for more information.

Issues and Contributions

If you encounter a bug or have a feature request, please create an issue. I'm not actively seeking contributions. However, if you have an improvement in mind, please open an issue first to discuss it before submitting a pull request.

About

PowerShell OAuth2.0/OpenID Connect (OIDC) Client.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published