Either the token is not expiring or I’m not understanding how an “expiration” works.
Using Postman, I first call /auth/credentials to login and obtain a token. This works. I then call a method /hello which is marked as [Authenticate] without supplying any credentials. I get a 200 so this works (Postman apparently using cookie from call to /auth/credentials). I then wait several minutes. I have ExpireTokensIn = TimeSpan.FromMinutes(1) in code. After 5 minutes I would expect a 401 when calling /hello but it continues to work, despite supposedly being expired.
My initial thought is that Postman is getting a refresh token but I think I debunked this after I locked the user account in the database and /hello continues to get a 200 despite the account being locked. So I would assume Postman is not able to refresh the token at this point.
Finally, calling /auth/logout logs me out and returns a 401 with a call to /hello. From that point on, I’m unable to get new credentials.
Make sure you’re not using Session Based Authentication as well, if you’re authenticating you need to specify UseTokenCookie=true which will return the User session encapsulated in the ss-tok JWT Token Cookie instead of populating the Server Session that’s referenced by Session Cookies.
I have no idea if I’m using Session Based Authentication. I just followed some examples on your website. This is the code I’m using to create the JwtAuthProvider:
container.Register<IDbConnectionFactory>(dbFactory);
container.Register<IAuthRepository>(c =>
new OrmLiteAuthRepository(dbFactory) { UseDistinctRoleTables = true });
//Create UserAuth RDBMS Tables
container.Resolve<IAuthRepository>().InitSchema();
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new JwtAuthProvider(AppSettings) {
AuthKey = AesUtils.CreateKey(),
AllowInQueryString = true,
AllowInFormData = true,
RequireSecureConnection = false,
ExpireTokensIn = TimeSpan.FromMinutes(1), // JWT Token Expiry
},
new CredentialsAuthProvider(AppSettings),
}));
The UseTokenCookie=true seems to be on the client side, so I’d prefer to do this on the server side.
I decoded the JWT per your suggestion and there is an “exp” value that appears to have the correct expiration time listed. However it does say “Invalid Signature”, so I don’t know if that has anything to do with it.
So what am I’m doing wrong in the above code that would be creating a Session Based Authentication?
Please read the docs on Authentication to gain a better understanding of how ServiceStack Auth works.
ServiceStack uses Sessions by default, you have to opt-in to use stateless JWT cookies as per my previous link to UseTokenCookie=true:
However this only establishes an Authenticated Session to a single Server that only lasts until the session stored on the Server is valid. The easiest way to tell ServiceStack to convert the Session into a stateless JWT Cookie instead is to set the UseTokenCookie option when authenticating, e.g:
What client/server side distinction? You have to populate the UseTokenCookie=true property on the Authenticate Request DTO the same as you would every other Service request.
Admittedly this topic is pretty daunting and despite all the information (maybe too much?) on your website, I just can’t seem to piece it all together. There does not seem to be any complete example to follow, and instead, bits and pieces here and there that you must put together to work.
I guess what I was trying to say is, from a “layman”, the idea of having the client (the web front end itself, that is calling the backend api to authenticate) do this means that the client is deciding to make this sessionless, not the server. But I want it to be sessionless on the server side, otherwise a client could simply not include this parameter and never have their token expire. Again, I may be totally wrong here, but from my testing it seems this is the case.
Let me try and further digest the information you provided to see if I can come up with something.
The client decides how they want to authenticate, just as they decide what provider they want to authenticate against. You’re looking for behavior that doesn’t exist.
You still need to go through the docs to understand of how JWT works which contains a number of client examples on the JWT docs like the UseTokenCookie=true example to specify that you want a stateless ss-tok JWT Token Cookie returned.
So it seems this is also on the client side. So what if client doesn’t utilize this code? When I say “client” I mean some third party client of mine that has their own web front end that is using (via CORS) my back end? How do I force them to use sessionless?
When I built Jwt Authentication with straight ASP.NET Core, it was by default sessionless and the client would expire without any extra effort. Are we saying that the Service Stack implementation doesn’t work that way? If so, why does it work differently?
ServiceStack uses session-based Auth by default, as mentioned several times in the docs and in comments here.
ServiceStack has used the same default for 10 years where ASP.NET has made several breaking changes to their Auth provider model within the same period. When you configure ASP.NET auth you are specifically configuring for stateless cookies, that is not the case with ServiceStack Auth, you’re registering all the Auth Providers you want available.
If you don’t register JwtAuthProvider most existing Auth Providers are Session Based, registering an additional JwtAuthProvider does not get to break all other existing auth providers - it’s just registering another Auth Provider that’s available, and ServiceStack allows you to convert an existing Session Based Auth to a stateless JWT Cookie.