Digest - mdaneri/Pode GitHub Wiki

Digest

Digest authentication allows secure user authentication without sending the password to the server. Instead, the client receives a challenge from the server and responds with a hash-based authentication response. The server then verifies the hash using the stored password as a secret key.

Pode's Digest Authentication is compliant with RFC 7616, ensuring compatibility with standard authentication mechanisms.

Setup

To configure Digest authentication in Pode, use the New-PodeAuthScheme -Digest function and pass it to Add-PodeAuth. The parameters supplied to the Add-PodeAuth function's ScriptBlock include the $username and a hashtable containing the authentication parameters extracted from the Authorization header:

Start-PodeServer {
    New-PodeAuthScheme -Digest -Algorithm "SHA-256" -QualityOfProtection "auth-int" | Add-PodeAuth -Name 'Authenticate' -Sessionless -ScriptBlock {
        param($username, $params)

        # check if the user is valid

        return @{ User = $user; Password = $password }
    }
}

Unlike other authentication methods, where only a user object is returned on success, Digest authentication requires returning the password (or hash) as a separate property. The password acts as the secret key to regenerate the client’s hash response for verification. Not returning the password results in an HTTP 401 Unauthorized challenge response.

RFC 7616 Compliance

Pode’s Digest authentication implementation adheres to RFC 7616, ensuring:

  • Use of nonce-based challenge-response authentication
  • Support for multiple hashing algorithms beyond MD5
  • Support for Quality of Protection (QoP), including auth and auth-int
  • Correct formatting of WWW-Authenticate headers on authentication failure

!!! note SHA-384 is not part of RFC 7616 but has been added for consistency with other modern cryptographic algorithms and to provide additional security options.

Supported Algorithms

Pode now supports multiple algorithms for Digest authentication. The -Algorithm parameter allows selecting one or more of the following:

  • MD5
  • SHA-1
  • SHA-256
  • SHA-384
  • SHA-512
  • SHA-512/256

Pode automatically includes all supported algorithms in the WWW-Authenticate challenge header, allowing clients to select the strongest available option.

Quality of Protection (QoP)

The -QualityOfProtection parameter (-qop) allows choosing between:

  • "auth" (authentication only)
  • "auth-int" (authentication with message integrity protection)

If auth-int is used, the client includes a hash of the request body in the authentication response, ensuring the request content has not been altered.

Handling Authentication Requests

By default, Pode checks if the request contains an Authorization header with the Digest scheme. The New-PodeAuthScheme -Digest function can be customized using the -HeaderTag parameter to modify the tag used in the request header. Pode also extracts all required parameters from the header, including the nonce, nonce count, and QoP options.

If the Authorization header is missing or invalid, Pode returns an HTTP 401 Unauthorized response with a WWW-Authenticate challenge.

Digest Authentication Parameters

The hashtable of parameters passed to the Add-PodeAuth function’s ScriptBlock includes the following:

Parameter Description
cnonce A nonce value generated by the client.
nc The count of times the client has used the server nonce.
nonce A nonce value generated by the server.
qop The quality of protection requested (auth or auth-int).
realm The authentication realm from the server's challenge.
response The hash generated by the client for authentication.
uri The URI path that requires authentication.
username The username provided for authentication.

Middleware

Digest authentication can be applied globally to all requests using Add-PodeAuthMiddleware or to specific routes via the -Authentication parameter.

Global Middleware

To apply Digest authentication globally to all routes:

Start-PodeServer {
    Add-PodeAuthMiddleware -Name 'GlobalAuthValidation' -Authentication 'Authenticate'
}

Per-Route Middleware

To enforce Digest authentication only on specific routes:

Start-PodeServer {
    Add-PodeRoute -Method Get -Path '/info' -Authentication 'Authenticate' -ScriptBlock {
        # logic
    }
}

Full Example

The following example sets up Digest authentication with SHA-256 and auth-int, validates a user, and applies authentication to a specific route:

Start-PodeServer {
    Add-PodeEndpoint -Address * -Port 8080 -Protocol Http

    # Setup Digest authentication with SHA-256 and auth-int
    New-PodeAuthScheme -Digest -Algorithm "SHA-256" -QualityOfProtection "auth-int" | Add-PodeAuth -Name 'Authenticate' -Sessionless -ScriptBlock {
        param($username, $params)

        # Example user validation
        if ($username -eq 'morty') {
            return @{
                User = @{
                    'ID' = 'M0R7Y302'
                    'Name' = 'Morty'
                    'Type' = 'Human'
                }
                Password = 'pickle'
            }
        }

        # Authentication failed
        return $null
    }

    # Protect the /cpu route with Digest authentication
    Add-PodeRoute -Method Get -Path '/cpu' -Authentication 'Authenticate' -ScriptBlock {
        Write-PodeJsonResponse -Value @{ 'cpu' = 82 }
    }

    # The /memory route is accessible without authentication
    Add-PodeRoute -Method Get -Path '/memory' -ScriptBlock {
        Write-PodeJsonResponse -Value @{ 'memory' = 14 }
    }
}

Windows-Specific Limitations and the Pode Client Module

Windows' built-in Digest authentication has several critical limitations that restrict its compatibility with modern security practices:

  • Limited to MD5: Windows does not support stronger hashing algorithms like SHA-256 or SHA-512.
  • No Support for auth-int: Integrity protection (auth-int) is not available, making it less secure.
  • Fails with Multiple Algorithms: If the WWW-Authenticate header lists multiple algorithms, Windows' built-in implementation fails to negotiate properly.
  • Lack of Algorithm Negotiation: Windows cannot automatically select the strongest supported algorithm from a list.

Overcoming Windows Limitations with the Pode Client Module

To bypass these Windows client limitations, Pode provides a custom client module that supports full RFC 7616-compliant Digest authentication. This module allows PowerShell scripts to authenticate using modern algorithms, multiple QoP modes, and cross-platform compatibility.

The client module is available under:

Import-Module ./examples/Authentication/Modules/Invoke-Digest.psm1

By using this module, you can perform secure Digest authentication in PowerShell, even on Windows, without being restricted to MD5-only authentication.

The module includes the following functions:

Invoke-WebRequestDigest

A replacement for Invoke-WebRequest that supports Digest authentication.

Example Usage

Import-Module './examples/Authentication/Modules/Invoke-Digest.psm1'

# Define the URI and credentials
$uri = 'http://localhost:8081/users'
$username = 'morty'
$password = 'pickle'

# Convert the password to a SecureString and create a credential object
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = [System.Management.Automation.PSCredential]::new($username, $securePassword)

# Make a GET request using Digest authentication
$response = Invoke-WebRequestDigest -Uri $uri -Method 'GET' -Credential $credential

# Display response headers and content
$response.Headers | Format-List
Write-Output $response.Content

Invoke-RestMethodDigest

A replacement for Invoke-RestMethod that supports Digest authentication.

Example Usage

Import-Module './examples/Authentication/Modules/Invoke-Digest.psm1'

# Define the URI and credentials
$uri = 'http://localhost:8081/users'
$username = 'morty'
$password = 'pickle'

# Convert the password to a SecureString and create a credential object
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = [System.Management.Automation.PSCredential]::new($username, $securePassword)

# Make a GET request and automatically parse JSON response
$response = Invoke-RestMethodDigest -Uri $uri -Method 'GET' -Credential $credential

# Output the parsed response
$response
⚠️ **GitHub.com Fallback** ⚠️