I am trying to create a session via an API token .
The request is sent successfully, I'm getting 3 cookies in the response, but their expiry date is the same as the time at which the request was sent, which invalidates them instantly.
For example, if the request is sent successfully on 20 April 2020, 00:24:29 this is the response:
Set-Cookie: persistent=XXXX; path=/; expires=Thu, 19-Mar-2020 00:24:30 GMT; secure; HttpOnly
Set-Cookie: onelogin.com_user=XXX; domain=.onelogin.com; path=/; expires=Mon, 20-Apr-2020 00:24:30 GMT; secure; HttpOnly
Set-Cookie: sub_session_onelogin.com=XXXXXXX; path=/; secure; HttpOnly
The second cookie that creates the session for using it on Onelogin is already expired.
Is there anything that is being done wrong? Any help would be much appreciated.
I am using HTTPS.
The initial API request to get the session token (note, not cookie) is a backend call from the app to the OneLogin API and so it is not visible in user browser, but you can see that that API call returns the JWT token with a 2 minute timeout to a customer app. You can navigate to https://jwt.io/ and click Debugger for verification. There will be an expiration area on the right side and you can hover over this to see the expiration. There is always a 2 minute timeout associated with it.
It is then the responsibility of your app to direct the user's browser to send the token in a HTTP payload to OneLogin at "/session_via_api_token", so as to provide a session cookie to the browser. You can use the SAML Tracer extension in your browser to capture a SAML trace to verify, by viewing the "HTTP" tab of the POST line for "session_via_api_token". Note: 3 cookies are set, of which 2 are persistent and are immediately set to expire - so they serve no purpose. So don't stress the fact that those 2 cookies are expired as it's not relevant. The key cookie is "subsession_onelogin.com" which is a session cookie and so has no expiry time in it. It is used to track session timeout.
If the user then attempts to get access to a OneLogin resource then it includes the new "subsession_onelogin.com" cookie and so is considered authenticated. OneLogin then issues an updated version of that cookie, which you can see in the SAML Trace on the GET line for the "sub_session.onelogin.com" Set-Cookie area.
It appears that the way the CORS method works for this API is slightly different than the form post method, and the API team has been made aware, as the Dev article will likely be updated to state that the form post method is suggested.
In addition, per my testing it appears that some browsers react differently, so testing other browsers would certainly shed more light. That is browser specific and as such wouldn't be related to the API calls. With the Create Session request on Safari when the default setting of "Prevent Cross Site Cookie Tracking" is enabled I have noticed that the cookies are returned as expected but the browser refuses to accept them. There is no warning or error in the browser console. It's unknown why Safari does this and can't find any documentation about it so that's a browser specific issue out of our control.
Browsers are making it harder so our API team will probably update our best practice guidelines in the coming months to say to use the form post redirect rather than CORS. The form post method should work for any and all browsers as they handle it different than the CORS method.
The first link in the API docs is https://developers.onelogin.com/api-docs/1/login-page/create-session-via-token and the second link to use it https://developers.onelogin.com/api-docs/1/login-page/create-session-login-token. You can then use https://jwt.io/ and click Debugger for verification. It's working properly with a 2 minute expiry which is correct. The key cookie is "subsession_onelogin.com" which is a session cookie and so has no expiry time in it as it is used to track session timeout.
In my tests I have verified that there is definitely a 2-minute lifetime, which is exactly how it should work. In my example tests it shows that the API response is claiming expiry at 16:19:04, which matches the jwt.io decoder (that site is useful for this). The 2nd part of the test returned the headers DATE parameter which shows the time of issue was 16:17:04; i.e. a 2 minutes before expiry. This is correct.
I imagine the problem you are having is caused by how your app directs the user's browser to invoke the "/session_via_api_token" call - if the app uses CORS then obviously you would need to include the relevant header. However, it appears that even with that header, some browsers will not send the CORS request (presumably due to browser security settings) and so the session never gets established. At least that is what I can see when using the sample custom login page in testing. Note: The first call is a REST API call (i.e. what Postman is good for), but the 2nd request is a regular browser request.
Related
I have a solution for an authentication system without using refresh token. Please tell me where are the vulnerabilities of this method.
I assume the following:
Client and Server are on the same domain.
Client is a browser that support HttpOnly cookie.
Client is using a Single Page Application.
The steps are:
User login by making a request to /api/auth with the credentials.
Server authenticate the user and send back a Set-Cookie Header with an HttpOnly cookie containing a JWT.
Client receive and set the HttpOnly cookie. Client also set in Local Storage a variable logged: true.
After sometime User reopen the browser. The Single Page Application check if the variable logged in Local Storage is == true. If so check if it still has the HttpOnly cookie by making a request to /api/check-cookie.
Server respond with true if it find the HttpOnly cookie and it is valid. Otherwise false.
Client, if receive false from /api/check-cookie, will prompt the user with the login.
With this approach the JWT can have a long expiration date and there is no need to keep track of refresh tokens.
Am I missing something?
I like your thinking and had similar ideas, particularly with setting a local storage variable to reflect the state as logged in so I could check that before making a pointless server call to refresh a token that potentially doesn't exist, however, I'm still using the refresh token.
I believe the crux of your issues will be when the user updates on the server side, it won't be reflected on the client side until the user re-authenticates with a new long-lasting, singular token as opposed to when the short-lived access token refreshes, setting the user again with the updated data.
I am using identityserver4 for all configured clients with "AccesssTokenType=1" i.e. reference type.
I have one web app hosted for server, and other one for clients.
I used default identityserver settings, which generated two cookie, one for session Id "idsrv.session", and other one for authentication "idsrv".
In logout I do signout
await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);
however it gives error when I call with "idsrv.session"
await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCheckSessionCookieName);
Issue / Steps to reproduce the problem
1st Iteration : Login on my client website which redirects to my identityserver application. I now interceprt the request and response using "Burp Suite". I copy the complete response which has redirect URL's and cookie details.
I signout/logout from client website.
2nd Iteration : I tried login again, and intercepted the request and response using Burp Suite, by passing wrong credential. While Intercepting the response I just copied the cookies from previous request (which was successful in my first iteration), and observe that identityserver has successfully validated the user using the cookie value, ignoring the wrong credentials in this iteration.
Even I tried invalidating and deleting cookies in my signout/logout method, but looks like identityserver still recognises it as the valid ones.
Brock Allen directed me to the corrrect solution. According to him :
This is the real issue you're asking about -- when you signout, you want the cookie to no longer be valid, even in the scenario when it's stolen and replayed. This is not something IdentityServer can address, because we use Microsoft's cookie authentication to achieve signin. You would have to fix this by changing the default usage of their component. You can do it by implementing "server-side cookie" (a term that I dislike) by implementing an ITicketStore: https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationOptions.cs#L136
Details Here
https://github.com/IdentityServer/IdentityServer4/issues/2565
When using the Postman Chrome App with the Interceptor extension it's easy to reuse the browser's cookies in order to log into an app and then call the services within.
Since moving to the Postman standalone app, this process has become somewhat manual. After logging in from the browser, I have to access the JSESSIONID cookie in the developer tools and copy its value over to postman.
When my session expires I need to repeat the process.
I would like to automate this synchronization or at least understand how I could obtain the new authenticated value in postman. It's important to note that none of the authentication mechanisms available in Postman work with my app which is why the manual login in the browser is necessary.
You can get JSESSIONID cookie in Postman Standalone in similar way your browser do it - by send proper requests (probably POST "login" request with user credentials) to server
I am using JMeter to make a simple login test on my website. I have a Thread Group which contains a Cookie Manager, an HTTP request to the root page, then an HTTP Post which posts a username and password, and then a Results view. When I run the test and view the response, the results show that the first HTTP request correctly calls set-cookie with the JSessionID, but the second HTTP request that POSTS credentials has no cookies - shouldn't this cookie be posted from the Cookie Manager? Thanks.
In most apps that I've tested, I don't see the actual cookie information after the initial request.
If your session isn't being maintained, there are a few quick things to check:
1. there are no hard coded JSessionID values in the HTTP Requests;
2. try different cookie manager types - different applications expect different settings.
normally browser stores and adds authentication header automaticly after successfull authentication.
I have a XMLHttpRequest and added the authentication header for basic auth. No problem at all.
Then I try to send a second request to the same url that is basic http protected without adding manually the http request header to this request. Poorly it seems that the browser is not storing the authentication provided in request 1. My goal is to add the authentication handler transparently to every request that follows the first one (like a native browser do).
Any idea? Thanks.
Browser only storing authetication requested from user. So, if you send 1st request w/o authentication fields, browser will prompt user for auth this time, remember credentials and use it for next requests transparently.