diff --git a/.gitignore b/.gitignore
index fb8d610..7be99fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -205,4 +205,8 @@ tools/
.idea
# Visual Studio Code workspace options
-.vscode
\ No newline at end of file
+.vscode/settings.json
+
+# Tokens stored by sample clients
+clients/*/proofkey
+clients/*/refresh_token
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..65a7459
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,59 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "ConsoleClientWithBrowser",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build-ConsoleClientWithBrowser",
+ "program": "${workspaceFolder}/clients/ConsoleClientWithBrowser/bin/Debug/net8.0/ConsoleClientWithBrowser.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/clients/ConsoleClientWithBrowser",
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "console": "externalTerminal"
+ },
+ {
+ "name": "ConsoleClientWithBrowserAndDPoP",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build-ConsoleClientWithBrowserAndDPoP",
+ "program": "${workspaceFolder}/clients/ConsoleClientWithBrowserAndDPoP/bin/Debug/net8.0/ConsoleClientWithBrowserAndDPoP.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/clients/ConsoleClientWithBrowserAndDPoP",
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "console": "externalTerminal"
+ },
+ {
+ "name": "ManualModeConsoleClient",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build-ManualModeConsoleClient",
+ "program": "${workspaceFolder}/clients/ManualModeConsoleClient/bin/Debug/net8.0-windows/ManualModeConsoleClient.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}/clients/ManualModeConsoleClient",
+ "serverReadyAction": {
+ "action": "openExternally",
+ "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
+ },
+ "env": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "console": "externalTerminal"
+ },
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..99e8cf0
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build-ConsoleClientWithBrowser",
+ "type": "process",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "${workspaceFolder}/clients/ConsoleClientWithBrowser/ConsoleClientWithBrowser.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "build-ConsoleClientWithBrowserAndDPoP",
+ "type": "process",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "${workspaceFolder}/clients/ConsoleClientWithBrowserAndDPoP/ConsoleClientWithBrowserAndDPoP.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "build-ManualModeConsoleClient",
+ "type": "process",
+ "command": "dotnet",
+ "args": [
+ "build",
+ "${workspaceFolder}/clients/ManualModeConsoleClient/ManualModeConsoleClient.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/IdentityModel.OidcClient.sln b/IdentityModel.OidcClient.sln
index ac54fb3..eb7f499 100644
--- a/IdentityModel.OidcClient.sln
+++ b/IdentityModel.OidcClient.sln
@@ -27,6 +27,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClientWithBrowserAnd
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrimmableAnalysis", "test\TrimmableAnalysis\TrimmableAnalysis.csproj", "{672FE4E9-9071-4C59-95FC-F265DF6B2FF5}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManualModeConsoleClient", "clients\ManualModeConsoleClient\ManualModeConsoleClient.csproj", "{864F9320-43C3-494E-946A-B19B4A7D1CA3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EB34682-F5A0-4F91-A624-64F042B5B910}"
+ ProjectSection(SolutionItems) = preProject
+ README.md = README.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -69,6 +76,10 @@ Global
{672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{672FE4E9-9071-4C59-95FC-F265DF6B2FF5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {864F9320-43C3-494E-946A-B19B4A7D1CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {864F9320-43C3-494E-946A-B19B4A7D1CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {864F9320-43C3-494E-946A-B19B4A7D1CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {864F9320-43C3-494E-946A-B19B4A7D1CA3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -83,6 +94,7 @@ Global
{0E1807AF-4142-4A3D-925C-BBA019E4E777} = {3DEB81D4-5B40-4D20-AC50-66D1CD6EA24A}
{7DDDA872-49C0-43F0-8B88-2531BF828DDE} = {A4154BEB-4B4A-4A48-B75D-B52432304F36}
{672FE4E9-9071-4C59-95FC-F265DF6B2FF5} = {3DEB81D4-5B40-4D20-AC50-66D1CD6EA24A}
+ {864F9320-43C3-494E-946A-B19B4A7D1CA3} = {A4154BEB-4B4A-4A48-B75D-B52432304F36}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {66951C2E-691F-408C-9283-F2455F390A9A}
diff --git a/clients/ConsoleClient/ConsoleClient.csproj b/clients/ConsoleClient/ConsoleClient.csproj
deleted file mode 100644
index 8aa6b48..0000000
--- a/clients/ConsoleClient/ConsoleClient.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- netcoreapp2.1
- Exe
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/clients/ConsoleClient/Program.cs b/clients/ConsoleClient/Program.cs
deleted file mode 100644
index 57d16e8..0000000
--- a/clients/ConsoleClient/Program.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using IdentityModel.OidcClient;
-using Microsoft.Net.Http.Server;
-using Newtonsoft.Json;
-using Serilog;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace ConsoleClient
-{
- public class Program
- {
- static string _authority = "https://demo.identityserver.io";
- static string _api = "https://api.identityserver.io/identity";
-
- public static void Main(string[] args) => MainAsync().GetAwaiter().GetResult();
-
- public static async Task MainAsync()
- {
- Console.WriteLine("+-----------------------+");
- Console.WriteLine("| Sign in with OIDC |");
- Console.WriteLine("+-----------------------+");
- Console.WriteLine("");
- Console.WriteLine("Press any key to sign in...");
- Console.ReadKey();
-
- await SignInAsync();
-
- Console.ReadKey();
- }
-
- private async static Task SignInAsync()
- {
- // create a redirect URI using an available port on the loopback address.
- string redirectUri = string.Format("http://127.0.0.1:7890/");
-
- // create an HttpListener to listen for requests on that redirect URI.
- var settings = new WebListenerSettings();
- settings.UrlPrefixes.Add(redirectUri);
- var http = new WebListener(settings);
-
- http.Start();
- Console.WriteLine("Listening..");
-
- var options = new OidcClientOptions
- {
- Authority = _authority,
- ClientId = "interactive.public",
- RedirectUri = redirectUri,
- Scope = "openid profile api",
- FilterClaims = true,
- LoadProfile = true
- };
-
- var serilog = new LoggerConfiguration()
- .MinimumLevel.Verbose()
- .Enrich.FromLogContext()
- .WriteTo.LiterateConsole(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}")
- .CreateLogger();
-
- options.LoggerFactory.AddSerilog(serilog);
-
- var client = new OidcClient(options);
- var state = await client.PrepareLoginAsync();
-
- OpenBrowser(state.StartUrl);
-
- var context = await http.AcceptAsync();
- var formData = GetRequestPostData(context.Request);
-
- if (formData == null)
- {
- Console.WriteLine("Invalid response");
- return;
- }
-
- await SendResponseAsync(context.Response);
-
- var result = await client.ProcessResponseAsync(formData, state);
-
- ShowResult(result);
- }
-
- private static void ShowResult(LoginResult result)
- {
- if (result.IsError)
- {
- Console.WriteLine("\n\nError:\n{0}", result.Error);
- return;
- }
-
- Console.WriteLine("\n\nClaims:");
- foreach (var claim in result.User.Claims)
- {
- Console.WriteLine("{0}: {1}", claim.Type, claim.Value);
- }
-
- Console.WriteLine($"\nidentity token: {result.IdentityToken}");
- Console.WriteLine($"access token: {result.AccessToken}");
- Console.WriteLine($"refresh token: {result?.RefreshToken ?? "none"}");
-
- var values = JsonConvert.DeserializeObject>(result.TokenResponse.Raw);
-
- Console.WriteLine($"Raw TokenResponse ...");
- foreach (var item in values)
- {
- Console.WriteLine($"{item.Key}: {item.Value}");
- }
-
- }
-
- private static async Task SendResponseAsync(Response response)
- {
- string responseString = $"Please return to the app.";
- var buffer = Encoding.UTF8.GetBytes(responseString);
-
- response.ContentLength = buffer.Length;
-
- var responseOutput = response.Body;
- await responseOutput.WriteAsync(buffer, 0, buffer.Length);
- responseOutput.Flush();
- }
-
- public static void OpenBrowser(string url)
- {
- try
- {
- Process.Start(url);
- }
- catch
- {
- // hack because of this: https://github.com/dotnet/corefx/issues/10361
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
- {
- url = url.Replace("&", "^&");
- Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
- }
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
- {
- Process.Start("xdg-open", url);
- }
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
- {
- Process.Start("open", url);
- }
- else
- {
- throw;
- }
- }
- }
-
- public static string GetRequestPostData(Request request)
- {
- if (!request.HasEntityBody)
- {
- return null;
- }
-
- using (var body = request.Body)
- {
- using (var reader = new StreamReader(body))
- {
- return reader.ReadToEnd();
- }
- }
- }
- }
-}
diff --git a/clients/ConsoleClientWithBrowser/ConsoleClientWithBrowser.csproj b/clients/ConsoleClientWithBrowser/ConsoleClientWithBrowser.csproj
index 67a5d52..9648a6c 100644
--- a/clients/ConsoleClientWithBrowser/ConsoleClientWithBrowser.csproj
+++ b/clients/ConsoleClientWithBrowser/ConsoleClientWithBrowser.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
Exe
diff --git a/clients/ConsoleClientWithBrowser/Program.cs b/clients/ConsoleClientWithBrowser/Program.cs
index 3ba5350..795e43b 100644
--- a/clients/ConsoleClientWithBrowser/Program.cs
+++ b/clients/ConsoleClientWithBrowser/Program.cs
@@ -96,7 +96,7 @@ private static async Task SignIn()
Browser = browser,
IdentityTokenValidator = new JwtHandlerIdentityTokenValidator(),
- RefreshTokenInnerHttpHandler = new SocketsHttpHandler()
+ RefreshTokenInnerHttpHandler = new SocketsHttpHandler(),
};
var serilog = new LoggerConfiguration()
diff --git a/clients/ConsoleClientWithBrowserAndDPoP/ConsoleClientWithBrowserAndDPoP.csproj b/clients/ConsoleClientWithBrowserAndDPoP/ConsoleClientWithBrowserAndDPoP.csproj
index e95b8de..b7fc863 100644
--- a/clients/ConsoleClientWithBrowserAndDPoP/ConsoleClientWithBrowserAndDPoP.csproj
+++ b/clients/ConsoleClientWithBrowserAndDPoP/ConsoleClientWithBrowserAndDPoP.csproj
@@ -1,7 +1,7 @@
- net6.0
+ net8.0
Exe
diff --git a/clients/ConsoleClientWithBrowserAndDPoP/Program.cs b/clients/ConsoleClientWithBrowserAndDPoP/Program.cs
index 60926fa..c3f82ea 100644
--- a/clients/ConsoleClientWithBrowserAndDPoP/Program.cs
+++ b/clients/ConsoleClientWithBrowserAndDPoP/Program.cs
@@ -47,7 +47,7 @@ private static async Task SignIn()
RedirectUri = redirectUri,
Scope = "openid profile api offline_access",
FilterClaims = false,
- Browser = browser,
+ Browser = browser
};
options.ConfigureDPoP(proofKey);
diff --git a/clients/ManualModeConsoleClient/ManualModeConsoleClient.csproj b/clients/ManualModeConsoleClient/ManualModeConsoleClient.csproj
new file mode 100644
index 0000000..cdee441
--- /dev/null
+++ b/clients/ManualModeConsoleClient/ManualModeConsoleClient.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0-windows
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/clients/ManualModeConsoleClient/Program.cs b/clients/ManualModeConsoleClient/Program.cs
new file mode 100644
index 0000000..64588b4
--- /dev/null
+++ b/clients/ManualModeConsoleClient/Program.cs
@@ -0,0 +1,109 @@
+using IdentityModel.OidcClient;
+using System.Diagnostics;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+
+Console.WriteLine("+-----------------------+");
+Console.WriteLine("| Sign in with OIDC |");
+Console.WriteLine("+-----------------------+");
+Console.WriteLine("");
+Console.WriteLine("Press any key to sign in...");
+Console.ReadKey();
+
+SignIn();
+
+Console.ReadKey();
+
+async void SignIn()
+{
+ // create a redirect URI using an available port on the loopback address.
+ string redirectUri = string.Format("http://127.0.0.1:7890/");
+ Console.WriteLine("redirect URI: " + redirectUri);
+
+ // create an HttpListener to listen for requests on that redirect URI.
+ var http = new HttpListener();
+ http.Prefixes.Add(redirectUri);
+ Console.WriteLine("Listening..");
+ http.Start();
+
+ var options = new OidcClientOptions
+ {
+ Authority = "https://demo.duendesoftware.com",
+ ClientId = "interactive.public",
+ Scope = "openid profile api",
+ RedirectUri = redirectUri,
+ };
+
+ var client = new OidcClient(options);
+ var state = await client.PrepareLoginAsync();
+
+ if(state.IsError)
+ {
+ Console.WriteLine($"Failed to create authentication state: {state.Error} - {state.ErrorDescription}");
+ http.Stop();
+ return;
+ }
+
+ Console.WriteLine($"Start URL: {state.StartUrl}");
+
+ // open system browser to start authentication
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = state.StartUrl,
+ UseShellExecute = true,
+ });
+
+ // wait for the authorization response.
+ var context = await http.GetContextAsync();
+
+ // sends an HTTP response to the browser.
+ var response = context.Response;
+ string responseString = string.Format("Please return to the app.");
+ var buffer = Encoding.UTF8.GetBytes(responseString);
+ response.ContentLength64 = buffer.Length;
+ var responseOutput = response.OutputStream;
+ await responseOutput.WriteAsync(buffer, 0, buffer.Length);
+ responseOutput.Close();
+
+ var result = await client.ProcessResponseAsync(context.Request.RawUrl, state);
+
+ BringConsoleToFront();
+
+ if (result.IsError)
+ {
+ Console.WriteLine("\n\nError:\n{0}", result.Error);
+ }
+ else
+ {
+ Console.WriteLine("\n\nClaims:");
+ foreach (var claim in result.User.Claims)
+ {
+ Console.WriteLine("{0}: {1}", claim.Type, claim.Value);
+ }
+
+ Console.WriteLine();
+ Console.WriteLine("Access token:\n{0}", result.AccessToken);
+
+ if (!string.IsNullOrWhiteSpace(result.RefreshToken))
+ {
+ Console.WriteLine("Refresh token:\n{0}", result.RefreshToken);
+ }
+ }
+
+ http.Stop();
+}
+
+// Hack to bring the Console window to front.
+// ref: http://stackoverflow.com/a/12066376
+[DllImport("kernel32.dll", ExactSpelling = true)]
+static extern IntPtr GetConsoleWindow();
+
+[DllImport("user32.dll")]
+[return: MarshalAs(UnmanagedType.Bool)]
+static extern bool SetForegroundWindow(IntPtr hWnd);
+
+void BringConsoleToFront()
+{
+ SetForegroundWindow(GetConsoleWindow());
+}
diff --git a/src/DPoP/DPoP.csproj b/src/DPoP/DPoP.csproj
index 61aa617..4a85bca 100644
--- a/src/DPoP/DPoP.csproj
+++ b/src/DPoP/DPoP.csproj
@@ -7,7 +7,7 @@
netstandard2.0;net6.0
latest
- enable
+ enable
OAuth2;OAuth 2.0;OpenID Connect;Security;Identity;IdentityServer;DPoP
DPoP extensions for IdentityModel.OidcClient
@@ -39,7 +39,7 @@
-
+
@@ -52,7 +52,7 @@
-
+
\ No newline at end of file
diff --git a/src/OidcClient/AuthorizeClient.cs b/src/OidcClient/AuthorizeClient.cs
index 3eee319..098f0b1 100644
--- a/src/OidcClient/AuthorizeClient.cs
+++ b/src/OidcClient/AuthorizeClient.cs
@@ -8,7 +8,6 @@
using IdentityModel.OidcClient.Results;
using Microsoft.Extensions.Logging;
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -44,9 +43,16 @@ public async Task AuthorizeAsync(AuthorizeRequest request,
AuthorizeResult result = new AuthorizeResult
{
- State = CreateAuthorizeState(request.ExtraParameters)
+ State = await CreateAuthorizeStateAsync(request.ExtraParameters)
};
+ if(result.State.IsError)
+ {
+ result.Error = result.State.Error;
+ result.ErrorDescription = result.State.ErrorDescription;
+ return result;
+ }
+
var browserOptions = new BrowserOptions(result.State.StartUrl, _options.RedirectUri)
{
Timeout = TimeSpan.FromSeconds(request.Timeout),
@@ -86,7 +92,7 @@ public async Task EndSessionAsync(LogoutRequest request,
return await _options.Browser.InvokeAsync(browserOptions, cancellationToken);
}
- public AuthorizeState CreateAuthorizeState(Parameters frontChannelParameters)
+ public async Task CreateAuthorizeStateAsync(Parameters frontChannelParameters)
{
_logger.LogTrace("CreateAuthorizeStateAsync");
@@ -99,13 +105,48 @@ public AuthorizeState CreateAuthorizeState(Parameters frontChannelParameters)
CodeVerifier = pkce.CodeVerifier,
};
- state.StartUrl = CreateAuthorizeUrl(state.State, pkce.CodeChallenge, frontChannelParameters);
+ if(_options.ProviderInformation.PushedAuthorizationRequestEndpoint.IsPresent() &&
+ !_options.DisablePushedAuthorization)
+ {
+ _logger.LogDebug("The IdentityProvider contains a pushed authorization request endpoint. Automatically pushing authorization parameters. Use DisablePushedAuthorization to opt out.");
+ var parResponse = await PushAuthorizationRequestAsync(state.State, pkce.CodeChallenge, frontChannelParameters);
+ if(parResponse.IsError)
+ {
+ _logger.LogError("Failed to push authorization parameters");
+
+ state.Error = parResponse.Error;
+ state.ErrorDescription = "Failed to push authorization parameters";
+ return state;
+ }
+ state.StartUrl = CreateAuthorizeUrl(parResponse.RequestUri, _options.ClientId);
+ }
+ else
+ {
+ state.StartUrl = CreateAuthorizeUrl(state.State, pkce.CodeChallenge, frontChannelParameters);
+ }
_logger.LogDebug(LogSerializer.Serialize(state));
return state;
}
+ private async Task PushAuthorizationRequestAsync(string state, string codeChallenge, Parameters frontChannelParameters)
+ {
+ var http = _options.CreateClient();
+ var par = new PushedAuthorizationRequest
+ {
+ Address = _options.ProviderInformation.PushedAuthorizationRequestEndpoint,
+ ClientId = _options.ClientId,
+
+ ClientSecret = _options.ClientSecret,
+ ClientAssertion = await _options.GetClientAssertionAsync(),
+
+ Parameters = CreateAuthorizeParameters(state, codeChallenge, frontChannelParameters),
+ };
+
+ return await http.PushAuthorizationAsync(par);
+ }
+
internal string CreateAuthorizeUrl(string state, string codeChallenge,
Parameters frontChannelParameters)
{
@@ -117,6 +158,20 @@ internal string CreateAuthorizeUrl(string state, string codeChallenge,
return request.Create(parameters);
}
+ internal string CreateAuthorizeUrl(string requestUri, string clientId)
+ {
+ _logger.LogTrace("CreateAuthorizeUrl with requestUri from PAR");
+
+ var parameters = new Parameters
+ {
+ { OidcConstants.AuthorizeRequest.ClientId, clientId },
+ { OidcConstants.AuthorizeRequest.RequestUri, requestUri }
+ };
+ var request = new RequestUrl(_options.ProviderInformation.AuthorizeEndpoint);
+
+ return request.Create(parameters);
+ }
+
internal string CreateEndSessionUrl(string endpoint, LogoutRequest request)
{
_logger.LogTrace("CreateEndSessionUrl");
diff --git a/src/OidcClient/AuthorizeState.cs b/src/OidcClient/AuthorizeState.cs
index f3f5ec2..541be71 100644
--- a/src/OidcClient/AuthorizeState.cs
+++ b/src/OidcClient/AuthorizeState.cs
@@ -7,7 +7,7 @@ namespace IdentityModel.OidcClient
///
/// Represents the state the needs to be hold between starting the authorize request and the response
///
- public class AuthorizeState
+ public class AuthorizeState : Result
{
///
/// Gets or sets the start URL.
diff --git a/src/OidcClient/OidcClient.cs b/src/OidcClient/OidcClient.cs
index afb4544..c84062c 100644
--- a/src/OidcClient/OidcClient.cs
+++ b/src/OidcClient/OidcClient.cs
@@ -109,7 +109,7 @@ public virtual async Task PrepareLoginAsync(Parameters frontChan
_logger.LogTrace("PrepareLoginAsync");
await EnsureConfigurationAsync(cancellationToken);
- return _authorizeClient.CreateAuthorizeState(frontChannelParameters);
+ return await _authorizeClient.CreateAuthorizeStateAsync(frontChannelParameters);
}
///
@@ -428,6 +428,7 @@ internal async Task EnsureProviderInformationAsync(CancellationToken cancellatio
KeySet = disco.KeySet,
AuthorizeEndpoint = disco.AuthorizeEndpoint,
+ PushedAuthorizationRequestEndpoint = disco.PushedAuthorizationRequestEndpoint,
TokenEndpoint = disco.TokenEndpoint,
EndSessionEndpoint = disco.EndSessionEndpoint,
UserInfoEndpoint = disco.UserInfoEndpoint,
diff --git a/src/OidcClient/OidcClientOptions.cs b/src/OidcClient/OidcClientOptions.cs
index 6d099c2..4c1bc80 100644
--- a/src/OidcClient/OidcClientOptions.cs
+++ b/src/OidcClient/OidcClientOptions.cs
@@ -181,7 +181,7 @@ public OidcClientOptions()
public HttpMessageHandler RefreshTokenInnerHttpHandler { get; set; }
///
- /// Gets or sets the HTTP handler used for back-channel communication (token and userinfo endpoint).
+ /// Gets or sets the HTTP handler used for back-channel communication (token, pushed authorization, and userinfo endpoints).
///
///
/// The backchannel handler.
@@ -259,5 +259,12 @@ public OidcClientOptions()
JwtClaimTypes.AccessTokenHash,
JwtClaimTypes.StateHash
};
+
+ ///
+ /// Gets or sets a flag to disable Pushed Authorization Requests (PAR).
+ /// By default, we use PAR when there is a configured PAR endpoint or
+ /// when the discovery endpoint indicates that it supports PAR.
+ ///
+ public bool DisablePushedAuthorization { get; set; } = false;
}
}
\ No newline at end of file
diff --git a/src/OidcClient/ProviderInformation.cs b/src/OidcClient/ProviderInformation.cs
index 73d02d4..e16d0fc 100644
--- a/src/OidcClient/ProviderInformation.cs
+++ b/src/OidcClient/ProviderInformation.cs
@@ -44,6 +44,14 @@ public class ProviderInformation
///
public string AuthorizeEndpoint { get; set; }
+ ///
+ /// Gets or sets the pushed authorization request (PAR) endpoint.
+ ///
+ ///
+ /// The PAR endpoint.
+ ///
+ public string PushedAuthorizationRequestEndpoint { get; set; }
+
///
/// Gets or sets the end session endpoint.
///
diff --git a/test/DPoPTests/DPoPTests.csproj b/test/DPoPTests/DPoPTests.csproj
index 56e309a..1e1d336 100644
--- a/test/DPoPTests/DPoPTests.csproj
+++ b/test/DPoPTests/DPoPTests.csproj
@@ -10,6 +10,10 @@
true
+
+ CS8002
+
+