dylanplecki / KeycloakOwinAuthentication

Keycloak Authentication Middleware for the C# OWIN Pipeline
http://keycloak.jboss.org
MIT License
56 stars 89 forks source link

Expired tokens at the beging #35

Open tzelve opened 8 years ago

tzelve commented 8 years ago

I try to use a demo app with very small ticket life (Access token 5 minutes and refresh token 15 minutes). From the first run i receive error "Both the access token and the refresh token have expired". I am in UTC+2 time zone and now (summer time) i am at UTC+3. I think this is the problem. I looked into the code on file KeycloakTokenHandler.cs and line 125, and i can see notBefore parsed from jwt parser but i think jwt parser didn't cast time to local time and later in KeycloakIdentity.cs on GetClaimsAsync you check datetimes as locals. So when i changed the KeycloakTokenHandler.cs and line 125 from: notBefore = jwt.ValidFrom; to: notBefore = ((long) jwt.Payload.Nbf.Value).ToDateTime(); (using must be include to see the extension function) everything working fine. Please check if this is feature or bug.

dylanplecki commented 8 years ago

Yes that's definitely a bug... If your OIDC client (i.e. webapp) is on a different local timezone than the Keycloak server you'll get this issue. I'll look into fixing it ASAP.

Probable fix would just to be to use Unix / Epoch time everywhere possible, or if not ensure everything is in UTC.

tzelve commented 8 years ago

Based on specification of jwt the exp,nbf and iat are NumericDate type, so .net jwt implementation is correct and it as utc. So I think the problem comes if your client's timezone is other than utc, not if your client's timezone is different that keycloak server. My previous suggestion to the code wasn't correct, i changed the KeycloakIdentity.cs on GetClaimsAsync where the checks happened. If you change DateTime.Now to DateTime.UtcNow works fine. Finally you must change the IsAuthenticated property.

dylanplecki commented 8 years ago

I think I may have skimmed over your first message, but you stated that you were using an access token and a refresh token both with 5 minute expiration times. Since they expire at the same time, after 5 minutes you'll be forced to log-out and re-login. Is this the issue which you're describing?

Also, I just took a preliminary look and it looks like Microsoft decodes the JWT exp and nbf fields into the application's local time, so it should work, but I'll do more testing on it.

tzelve commented 8 years ago

It was a typo error on my first comment, not i have already fixed it (5 min token, 15 minutes refresh). From the source code of i can see the Expires and notBefore are in utc (as spec says):

this[JwtRegisteredClaimNames.Exp] = EpochTime.GetIntDate(expires.Value.ToUniversalTime());
...
this[JwtRegisteredClaimNames.Nbf] = EpochTime.GetIntDate(notBefore.Value.ToUniversalTime());

Sorry for my typo.