openiddict-core icon indicating copy to clipboard operation
openiddict-core copied to clipboard

Silent auth failures after upgrading from .NET 5 to 6 and related libraries like OpenIddict.EntityFrameworkCore from 3.0.3 to 3.1.1

Open jeremycook opened this issue 2 years ago • 5 comments

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

  • [X] I confirm I'm a sponsor or a contributor

Version

3.x

Describe the bug

After upgrading from .NET 5 to 6, EF Core 5 to 6, and OpenIddict.EntityFrameworkCore 3.0.3 to 3.1.1 I started getting the OpenIdConnectProtocolException: Message contains error: 'invalid_grant', error_description: 'The specified authorization code is no longer valid.' errors.

I fixed the issue by using pgAdmin 4's Schema Diff tool to compare the 3.0.3 and 3.1.1 schemas. It generated a script like the following one. After applying this script the error went away and authentication started working again.

I believe the problem is with the change to timestamp with time zone. The newer version assumes time zone information is available, but the old database schema did not have it. That difference in schema wasn't fatal and wouldn't generate an exception, but it would cause these auth failures that made it seem like the code had expired when really the time zone was just shifted.

I don't have a suggestion for how this should be resolved. Maybe just a note in the migration guide, I don't know.

WARNING: I recommend you use Schema Diff to generate your own migration script, and not just copy this verbatim. This is here to give you an idea of what may have changed and things you can look into.

-- This script was generated by the Schema Diff utility in pgAdmin 4. 
BEGIN;

-- Added as recommended at https://www.npgsql.org/efcore/release-notes/6.0.html#migrating-columns-from-timestamp-to-timestamptz
SET TimeZone='UTC';

DROP FUNCTION IF EXISTS public.delete_cascade(p_schema character varying, p_table character varying, p_key character varying, p_recursion character varying[]);

ALTER TABLE public."OpenIddictAuthorizations"
    ALTER COLUMN "CreationDate" TYPE timestamp with time zone ;
ALTER TABLE IF EXISTS public."OpenIddictAuthorizations" DROP CONSTRAINT IF EXISTS "FK_OpenIddictAuthorizations_OpenIddictApplications_Application~";

ALTER TABLE IF EXISTS public."OpenIddictAuthorizations"
    ADD CONSTRAINT "FK_OpenIddictAuthorizations_OpenIddictApplications_Application~" FOREIGN KEY ("ApplicationId")
    REFERENCES public."OpenIddictApplications" ("Id") MATCH SIMPLE
    ON UPDATE NO ACTION
    ON DELETE NO ACTION;

ALTER TABLE public."OpenIddictTokens"
    ALTER COLUMN "CreationDate" TYPE timestamp with time zone ;

ALTER TABLE public."OpenIddictTokens"
    ALTER COLUMN "ExpirationDate" TYPE timestamp with time zone ;

ALTER TABLE public."OpenIddictTokens"
    ALTER COLUMN "RedemptionDate" TYPE timestamp with time zone ;
ALTER TABLE IF EXISTS public."OpenIddictTokens" DROP CONSTRAINT IF EXISTS "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId";

ALTER TABLE IF EXISTS public."OpenIddictTokens" DROP CONSTRAINT IF EXISTS "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId";

ALTER TABLE IF EXISTS public."OpenIddictTokens"
    ADD CONSTRAINT "FK_OpenIddictTokens_OpenIddictApplications_ApplicationId" FOREIGN KEY ("ApplicationId")
    REFERENCES public."OpenIddictApplications" ("Id") MATCH SIMPLE
    ON UPDATE NO ACTION
    ON DELETE NO ACTION;

ALTER TABLE IF EXISTS public."OpenIddictTokens"
    ADD CONSTRAINT "FK_OpenIddictTokens_OpenIddictAuthorizations_AuthorizationId" FOREIGN KEY ("AuthorizationId")
    REFERENCES public."OpenIddictAuthorizations" ("Id") MATCH SIMPLE
    ON UPDATE NO ACTION
    ON DELETE NO ACTION;

END;

Also posted here: https://stackoverflow.com/a/72508275/1945957

To reproduce

  • Upgrade OpenIddict.EntityFrameworkCore from 3.0.3 to 3.1.1
  • Try to authenticate from a client that had been working fine
  • Client gets OpenIdConnectProtocolException: Message contains error: 'invalid_grant', error_description: 'The specified authorization code is no longer valid.'

Exceptions (if any)

OpenIdConnectProtocolException: Message contains error: 'invalid_grant', error_description: 'The specified authorization code is no longer valid.

jeremycook avatar Jun 05 '22 14:06 jeremycook

  • Upgrade OpenIddict.EntityFrameworkCore from 3.0.3 to 3.1.1

It's interesting because there was no schema/DB change between those two versions: https://github.com/openiddict/openiddict-core/compare/3.0.3...3.1.1

The only thing that changed between the two that could be related is the Entity Framework Core version targeted by OpenIddict: a change in EF Core itself may explain the difference. I also heard there was various changes regarding DateTime in npgsql too, so it could be related.

kevinchalet avatar Jun 05 '22 18:06 kevinchalet

I'm sure you're right that it is related to some difference between EF core 5 and 6. I meant to also include that I upgraded to .net 6 and EF core 6 at the same time, and forgot. I'll also update my answer on stack overflow as soon as I can.

jeremycook avatar Jun 05 '22 23:06 jeremycook

I can confirm, experiencing the same bug. I also have upgraded a huge number of EF-related packages, not only OpenIddict. Temporary solved using in-memory db.

a-a-k avatar Jun 06 '22 05:06 a-a-k

now I fixed that finally by adding the following code for legacy compatibility:

public AuthDbContext(DbContextOptions<AuthDbContext> options)
    : base(options)
{
    AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
}

https://www.npgsql.org/efcore/release-notes/6.0.html#opting-out-of-the-new-timestamp-mapping-logic

a-a-k avatar Jun 06 '22 07:06 a-a-k

For completeness here are the Npgsql EF Core 6.0 instructions for Migrating columns from timestamp to timestamptz.

jeremycook avatar Jun 06 '22 13:06 jeremycook