openiddict / openiddict-core

Flexible and versatile OAuth 2.0/OpenID Connect stack for .NET
https://openiddict.com/
Apache License 2.0
4.44k stars 520 forks source link

Shorting the returned code in the Authorisation Code with PKCE implementation #1843

Closed AKlaus closed 1 year ago

AKlaus commented 1 year ago

Confirm you've already contributed to this project or that you sponsor it

Describe the solution you'd like

Regarding the Authorisation Code with PKCE (RFC 7636) implementation with no authorization storage (e.g. for the Degraded mode) and hence no reference tokens in use.

The server returns the Code (encrypted by default) wrapped in a signed JWT by calling link to GenerateIdentityModelToken.ValueTask() method: context.Token = context.SecurityTokenHandler.CreateToken(descriptor). This (especially the signature) blows out the size of the generated code string (becomes > 2,048 symbols) that gets returned in the Query String.

Problem: Due to the heavy size of the token, in its turn, the client's request may hit limitations on the Query String and/or URL length.

It'd be great if it was possible to keep the generated code string well under 2,048 symbols.

Is there an easy way to either:

Full disclosure – I'm an indirect contributor, who blogged about OpenIddict with examples on GitHub.

Additional context

No response

kevinchalet commented 1 year ago

not wrapping the code in a JWT (or at least not signing it)? or

It's not wrapped: the authorization code is an encrypted and signed JWT. For obvious reasons, disabling encryption or signing is absolutely not recommended, as it would allow anyone to tamper with the claims contained in the authorization code.

sending back a short (<100 symbols) reference to the code with using a memory cache (it'd bearly keep it under 2,000 symbols)?

When disabling token storage (e.g when using the degraded mode), you're responsible for implementing this logic. For that, you need:

When token storage is enabled, it's performed by these two handlers, if you need some inspiration:

https://github.com/openiddict/openiddict-core/blob/7915f28d90d61fa7a3d34ed20ca8b56c0dd5eb26/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs#L1304-L1396

https://github.com/openiddict/openiddict-core/blob/7915f28d90d61fa7a3d34ed20ca8b56c0dd5eb26/src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs#L146-L267

Alternatively, you could try registering a SymmetricSecurityKey using options.AddSigningKey(...) (HMAC-SHA256 produces smaller "signatures" than RSA-SHA256) or use the ASP.NET Core Data Protection integration package (options.UseDataProtection()), that also relies on symmetric encryption and HMAC and should produce smaller tokens. In any case, OpenIddict makes no guarantee that the generated tokens will be under a specific length.

AKlaus commented 1 year ago

Thank you for pointing me in the right direction.

I implemented a working solution here in this PR: AKlaus/Transparent-Auth-Gateway/pull/2. What would be a reasonable expiration for the auth code reference? I set it to 1 min. Is it too small/long?

P.S. I understand the limitations of memory cache vs distributed. But the auth servers usually experience quite a modest load and the need of scaling them out would require a significant volume of users.

kevinchalet commented 1 year ago

What would be a reasonable expiration for the auth code reference? I set it to 1 min. Is it too small/long?

1 minute is on the low side, but shouldn't be a problem in most cases (except perhaps for heavily loaded clients that won't be able to redeem the authorization code within a single minute).

AKlaus commented 1 year ago

Just curious if you considered using a zipped auth code (with a password instead of encrypting it) to reduce the query string length.

kevinchalet commented 1 year ago

Compression is rarely used as it makes tokens potentially vulnerable to BREACH/CRIME-like attacks (even ASP.NET Core Data Protection doesn't use compression for the same reason).