Skip to content

Support for Pushed Authorization Requests in OidcHandler #51686

Closed

Description

Image for: Description

Background and Motivation

Image for: Background and Motivation

Pushed Authorization Requests (PAR) is a relatively new OAuth standard that improves the security of OAuth and OIDC flows by moving authorization parameters from the front channel to the back channel (that is, from redirect URLs in the browser to direct machine to machine http calls on the back end).

This prevents an attacker in the browser from

  • seeing authorization parameters (which could leak PII) and from
  • tampering with those parameters (e.g., the attacker could change the scope of access being requested).

Pushing the authorization parameters also keeps request URLs short. Authorize parameters might get very long when using more complex OAuth and OIDC features such as Rich Authorization Requests, and URLs that are long cause issues in many browsers and networking infrastructure.

The use of PAR is encouraged by the FAPI working group within the OpenID Foundation. For example, the FAPI2.0 Security Profile requires the use of PAR. This security profile is used by many of the groups working on open banking (primarily in Europe), in health care, and in other industries with high security requirements.

PAR is supported by a number of identity providers, including

  • Duende IdentityServer
  • Curity
  • Keycloak
  • Authlete

This proposal aims to add support for PAR to the OidcHandler.

Proposed API

Image for: Proposed API

We need a new flag to enable the behavior:

namespace Microsoft.AspNetCore.Authentication.OpenIdConnect;

public class OpenIdConnectOptions
{
+    /// <summary>
+    /// Flag to set whether the handler should push authorization parameters on the backchannel before 
+    /// redirecting to the identity provider.
+    /// The default is 'false'.
+    /// </summary>
+    public bool UsePushedAuthorization { get; set; } 
}

And we need new properties on the OpenIdConnectConfiguration to describe the PAR-specific information we get from discovery (and use for manual configuration).

namespace Microsoft.IdentityModel.Protocols.OpenIdConnect;

public class OpenIdConnectConfiguration
{
+    //
+    // Summary:
+    //     Gets or sets the 'pushed_authorization_request_endpoint'.
+    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = "pushed_authorization_request_endpoint", Required = Required.Default)]
+    public string PushedAuthorizationRequestEndpoint { get; set; }
+
+    //
+    // Summary:
+    //     Boolean parameter indicating whether the authorization server accepts authorization request 
+    //     data only via PAR. Dafault Value is false.
+    [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, PropertyName = "require_pushed_authorization_requests", Required = Required.Default)]
+    public bool RequirePushedAuthorizationRequests { get; set; }

}

When the UsePushedAuthorization flag is enabled in configuration or the require_pushed_authorization_requests flag is enabled in the discovery document or the explicit configuration, the parameters that the handler would normally set in the URL when it redirects to the authorize endpoint will instead be sent on a backchannel call to the PAR endpoint, and the resulting request_uri will instead be attached to the redirect, along with the client_id, as per the specification.

It is an error to attempt to enable UsePushedAuthorization with an identity provider that publishes a discovery document without a pushed_authorization_request_endpoint (which indicates that the server does not support PAR) or with explicit configuration that does not set the PushedAuthorizationRequestEndpoint.

It is also an error to attempt to disable UsePushedAuthorization with an identity provider that publishes a discovery document that enables require_pushed_authorization_requests or with explicit configuration that enables the RequirePushedAuthorizationRequests flag.

Usage Examples

Image for: Usage Examples
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = "cookie";
                options.DefaultChallengeScheme = "oidc";
            })
                .AddCookie("cookie")
                .AddOpenIdConnect("oidc", options =>
                {
                    options.Authority = "https://localhost:5001";

                    options.ClientId = "par";
                    options.ClientSecret = "secret";

                    options.ResponseType = "code";
                    options.UsePkce = true;

                    options.UsePushedAuthorization = true; // <------ New flag on
                })

Alternative Designs

Image for: Alternative Designs

Instead of adding support for PAR directly to the handler, we could instead allow users of the handler to implement PAR themselves within events. The challenge with the events is that the best currently existing event to use for that purpose is the OnRedirectToIdentityProvider event, and it is raised before the state parameter is computed. There are a couple of ways that I see to work around this:

  • Users could make an event that does the following:
  1. Copy the state parameter computation from the handler
  2. Push the authorization parameters (including state)
  3. Change the redirect url to use the client id and request uri
  4. Copy the rest of the logic of the event handler (without the state parameter computation)
  • Another alternative is to add a new event that fires later in the process - immediately after the state parameter is computed. Naming this event is a little tricky, since we already have OnRedirectToIdentityProvider, and this would also happen when redirecting to the identity provider, just later in the process. If such an even existed, then users of the handler could add use that event to push the authorization parameters and change the redirect url, without needing to copy large amounts of code from the handler into their event.

These two approaches are demonstrated here.

Risks

Image for: Risks

This is a low risk change. Users would have to opt in to get the new behavior. Existing Oidc scheme configurations are unaffected.

We are making a new outgoing HTTP request to implement this specification, but we're making the request to a url that was supplied by the OIDC authority through the discovery document or directly by the developer using the explicit configuration in the handler.

Metadata

Image for: Metadata

Metadata

Image for: Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-authIncludes: Authn, Authz, OAuth, OIDC, BearerenhancementThis issue represents an ask for new feature or an enhancement to an existing one

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Image for: Issue actions