Web Connection
Odd session cookie reset
Gravatar is a globally recognized avatar based on your email address. Odd session cookie reset
  Richard Kaye
  All
  Feb 19, 2025 @ 07:32am

As promised, this was a bit weird and at the moment it's solved but I figure I should mention.

In anticipation of rolling out 8.2 to my production environments I updated the wwRequestLog and wwSession structures in SQL per our other conversation, poked around in my dev and stage, and everything seemed fine. These were still running 8.1.2 at the time. I still wanted to do more testing with 8.2 but figured having those columns changed from varchars with limits to text should have no impact in my production DB. (BTW it would be nice if nulls were supported in those tables as changing the structure can take a little time when there are a lot of rows. At least in my experience, structure updates to tables with nullable columns are much faster in SQL.) So I updated the tables over the weekend and figured all was well. Yesterday I started getting reports of sessions timing out after 20 minutes, and to be honest I started noticing that behavior during my work day but didn't pay close attention. Well, I should have as my users were getting peeved. This morning I was able to see that the session cookie that gets created upon logging in was indeed set to expire after 20 minutes but my config.web has a 12 hour lifetime. OTOH the new session cookie created after logging out was set to the full 12 hours. This accelerated my testing of 8.2 where I saw the session cookies properly retaining the proper lifetime regardless of logging in/out.

The TL;DR is that deploying 8.2 fixed the problem, but I'm puzzled if/how that connected to the table structure updates. I'm also wondering if I need to push those experimental updates related to UserSecurity class and cookie handling sooner rather than later, but also unsure if I should be drawing a straight line between these issues.

As always, your thoughts appreciated.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 19, 2025 @ 09:33am

That might be caused by the bug that I fixed in the cookie handling. There was a path through there were the cookie was not being set correctly or being set to its default and never updated for proper session timeout.

Give the update process class a try and see if that fixes the issue.

It doesn't happen all the time - I'm running the code here on this site, and the session cookie is definitely holding it's login across browser sessions, so it's only certain situations that seem to trigger the issue with the cookie not being set properly.

IAC - it sounds very similar to the fix, so start there...

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 19, 2025 @ 09:44am

The problem with testing/catching this one is leaving your browser alone for 20 minutes. I think I'll add some debug logging to save the cookie expiration date out to disk.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 19, 2025 @ 09:49am

You can check for cookie expiration in the Web Browser Tools -> Application:

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 19, 2025 @ 10:36am

Yeah, that's how I knew it was betting overridden. Now I'm trying to figure out how to retrieve that timestamp programmatically, preferably after the InitSession call so I can write to a log file. Using request.getcookie gets me the value but not the rest of the cookie attributes. Strolling through the fine documentation looking for clues...

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 19, 2025 @ 11:47am

Your last reply doesn't show up here?

I did as you suggested and checked that string. I can see my session cookie (_RFC3) but not the Expires attribute? Here's the full string returned by Request.GetExtraHeader("Cookie").

_evga_d902=73329777c53aa467.; _ga=GA1.1.1205361580.1738191485; userty.core.p.26c6a7=__2VySWQiOiI2YTJmN2M2ZDdhOGE4ZjNkN2ZhYzk2YTU0ZGY4NDVmYyJ9eyJ1c; _hp2_id.4149576013=%7B%22userId%22%3A%223269837666262771%22%2C%22pageviewId%22%3A%221769451684836655%22%2C%22sessionId%22%3A%223393045546986804%22%2C%22identity%22%3Anull%2C%22trackerVersion%22%3A%224.0%22%7D; AZTOKEN-PROD=BEE54EB8-BA44-4220-B78D-A0CB878742F1; _hp2_props.4149576013=%7B%22authState%22%3A%22logged-out%22%2C%22whaleStatus%22%3A%22false%22%2C%22localized_timezone%22%3A%22enabled%22%2C%22Onboarding_PROD_Experience%22%3A%22experience%22%2C%22Search%20Type%20Ahead%22%3A%22control%22%2C%22DownloadAppViaSMS%22%3A%22experience%22%7D; userty.core.s.26c6a7=__WQiOiI1ODcxOGJhYzVhNTQ5Mzg0NzQ4ZmQ2ZGUyOTk0MTM4MCIsInN0IjoxNzM5OTEzMTQ0OTcwLCJyZWFkeSI6dHJ1ZSwid3MiOiJ7XCJ3XCI6MTQwOSxcImhcIjoxMDExfSIsInNlIjoxNzM5OTE1MjAzMzgwLCJwdiI6MX0=eyJza; _ga_0K6YBFZV6P=GS1.1.1739913144.3.1.1739913408.60.0.0; _RFC3=QS8QxJpqFiUKp3bd; _hp2_id.4255411065=%7B%22userId%22%3A%22524086738135855%22%2C%22pageviewId%22%3A%225419881682109751%22%2C%22sessionId%22%3A%226369572558343090%22%2C%22identity%22%3Anull%2C%22trackerVersion%22%3A%224.0%22%7D

Am I being silly expecting to see any of the other cookie properties as clear text or otherwise labelled in a way that will let me pull out the relevant characters more easily?

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 19, 2025 @ 11:52am

I've deployed a stage build with the updates to wwProcess and wwPageResponse. I see this when I have an authenticated session:

It shows "Session" for Expires/Max-Age. Is this the intended behavior?

For context, using the current 8.2 release I see this for an authenticated session:

That's showing the 12 hour value I'm used to seeing.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 19, 2025 @ 09:08pm

Well - looks like the 8.2 version is doing the right thing. The deployed version is not.

Or are you saying you shouldn't have a non-expiring cookie?

Note that you have to re-login to force the cookie to be set again...

I initially posted that you can extract the cookie, that shows up in Web Connection is retrieved from the Web Server and doesn't include any of the cookie's settings including the expiration - the browser manages that internally via the Application settings stored on the client and only forwards the cookie information when the cookie is valid - IOW, the cookie is validated and passed to the server on the client - if expired it's not sent. It's always up to the client to manage cookie lifetime, but the server initially determines what rules apply to the cookie (ie. expiration if any, secureonly, first party only etc.) and the browser parses that only forwards the cookie if the rules are met.

Note that other HTTP clients can send a cookie arbitrarily. For example, you can pass a cookie to a server by value even if that cookie has expired - there really is no such thing as an expired cookie outside of a browser or a client that properly manages cookies (WebSurge actually uses a .NET Cookie container and it does the right thing, but that' not a requirement).

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 19, 2025 @ 09:17pm

Best thing to do is to set a breakpoint on the code in wwProcess::Authenticate() where the cookie is set and see how it is set.

I actually have this code now (and in the Experimental zip):

*** Login Form Postbase logic here
IF Request.IsPostBack()
	*** Retrieve the default form field values
	lcUsername = Request.Form("WebLogin_txtUsername")
	lcPassword = Request.Form("WebLogin_txtPassword")
																				
	*** Check and see whether this user is authenticated
	IF this.OnAuthenticateUser(lcUserName,lcPassword,@lcErrorMsg)		 
		*** Assign auth user and write into Session
		IF EMPTY(this.cAuthenticatedUser)
			this.cAuthenticatedUser = lcUsername
		ENDIF
		Session.SetSessionVar(this.cAuthenticationUserSecurityKey,lcUsername)
		
*** THIS BLOCK
		ltDate = {:} && Empty Date
		IF Request.IsChecked("WebLogin_chkRememberMe")					
			ltDate = DATETIME() + this.nAuthenticationTimeoutSeconds
		ENDIF   
		THIS.oResponse.AddCookie(this.cSessionKey,Session.cSessionId,"/",ltDate,"",.T.,.F.)	
*** ENDBLOCK
			
		*** Override Page setting so it doesn't
		*** look like a Postback after validation
		IF VARTYPE(__WebPage) = "O"
				__WebPage.IsPostBack = .F.
		ENDIF
		
		THIS.OnAuthenticated()   
		RETURN .T.
	ENDIF		

That code is responsible for setting the cookie and it sets it based on the Remember me checkbox. Make sure that's checked - if it's not then the cookie isn't stored and is just a session cookie (ie. the empty date path).

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 19, 2025 @ 09:48pm

The more I think about this code fix, the more I realize that I don't remember all of what happens here... 😄

I just stepped through an entire auth request and the way the code used to work was this.

  • Login
  • By default the default Session Timeout is used for expiration
  • Cookie for Session is set in InitSession()
  • If you log in with Remember Me
  • Cookie is reset explicitly with the authentication timeout

IOW, the default Cookie behavior is set by whatever InitSession() sets up using Session timeout settings. Then if Remember Me is ticked it essentially overwrites the original cookie with a new cookie.

I believe this is actually the desired behavior - that's the way it should work.

So I think the change I made has to be rolled back. I think what's happening is that your app is using the default Session timeout (which is not Session default and has an expiration date) and my code change was effectively wiping out the default cookie and creating a new default Session cookie without a timeout - which is wrong.

So the old code mostly does the right thing - what it doesn't do though is set the cookie in the same way that InitSession does with all the extra cookie settings applied. I'm looking into that now but I think they are not all available when Authenticate() is called.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Rick Strahl
  Feb 19, 2025 @ 11:06pm

So I've verified that the old code works and have also fixed the cookie issue. But that introduced another change in wwSession which also has to be updated and is updated in the Web Connection Experimental files now.

The code change is basically reverted back to the original but adds the explict full cookie creation so it matches the InitSession() session cookie creation:

IF Request.IsChecked("WebLogin_chkRememberMe")					
	LOCAL ltDate
	ltDate = DATETIME() + this.nAuthenticationTimeoutSeconds
	
	*** Override the Session Key with custom settings 
	LOCAL loCookie
	loCookie = CREATEOBJECT("wwCookie")
	loCookie.CookieName = this.cSessionKey
	loCookie.Value = Session.cSessionId
	loCookie.Expires = ltDate	
	loCookie.SameSite = "strict"
	loCookie.Secure = Session.lIsSecureCookie  && <-- This is a new propert in wwSession.prg
	loCookie.HttpOnly = .T.

	*** Web Control Page
	*** Force HTML object to add the Cookie in Header creation
	this.oResponse.AddCookie(loCookie)
ENDIF

Note no Cookie is set if you don't check the Remember me checkbox.

Note that session also has a session time - if you set this timeout, by default that same timeout is applied to nAuthenticationTimeout unless you overwrite it explicitly. If you use the default behavior - effectively the checkbox operation has no effect as the default cookie already has a timeout.

Maybe this code should actually be adjusted to explicitly always set the cookie and either set the timeout or leave it empty here. This will override the default session behavior once you log in.

+++ Rick ---

+++

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 20, 2025 @ 04:30am

Thanks, Rick.

The intention with my app is to have the explicit 12-hour lifetime for the session. I do understand that logging out effectively creates a new session and that session is used for the next login.

To your point about the proper implementation of the session cookie, here's what I'm doing. This is what I have in the USM OnProcessInit:InitSession call:

this.InitSession(this.oConfig.cCookieName,43200,.t.)

Here's the call to OnProcessInit:InitSession in my main process class:

this.InitSession(Server.oConfig.oUserSecurityManagerProcess.cCookieName,43200,.T.)

Am I doing this the right way?

I've got this in its own branch so I can play before deploying to production. I will mention that I have not implemented the remember me checkbox in my login page. I'll deploy the latest experimental to that branch and let you know what I see.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 20, 2025 @ 04:38am

Hmmm... I know this operator made an error last time with the experimental zip but the one I just dled from the link in your last message shows no differences from the prior one for the 2 PRGs in question.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 20, 2025 @ 09:04am

That's not what's online...

Make sure you don't have a cached version of the file...

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 20, 2025 @ 09:46am

I'll hit that URL from an incognito session and see what comes through.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 20, 2025 @ 10:31am

User Security uses Session, so they both use the same cookie - there's no need to screw around with the cookie name.

I'd recommend to set your timeout in InitSession() and forget about it.

The one thing that is broken I believe (further investigation is required) is when you log in and you don't check Remember Me it actually still remembers you because the original session cookie is applied. So if the default session has a timeout of x that timeout will still be used.

The fix for this I think is to properly manage the Cookie collection in wwPageResponse. Currently I write out a cookie value string into the collection. It would be much cleaner if I write out the cookie object instead. Then Authenticate() could just update the existing cookie by adding or removing the expiration without having to have all the rest of the cookie state information available.

The problem is legacy code which can/could specify specific values. That can be fixed but it's not a quick fix that needs to be thoroughly tested.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 20, 2025 @ 01:07pm

Trying to wrap my head around what you're telling me. 😃

Am I not setting the timeout value now in the InitSession call(s)?
Should I not be setting session in both processes (main & USM)?
Also, I am sharing the cookie as I also thought was the recommended approach when chaining process objects?

I've been dealing with some other plumbing issues so haven't had a chance to try out the latest experimental. That's next on my list.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Rick Strahl
  Richard Kaye
  Feb 20, 2025 @ 08:30pm

I'm not really telling you anything - I'm just relaying some thoughts on the process and how it works.

If you have two processes that are both sharing the same session, make sure that InitSession() uses the same session keys and same expirations. If you do that it should all just work as is.

The changes are related to the way the authentication flows through the session manager - it's internal stuff that you don't really control. The bug I introduced with the original change was that I was overwriting the session cookie when it should only be set in the specific case.

+++ Rick ---

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 21, 2025 @ 02:45am

Thanks, Rick. Pretty sure that's what I'm doing but it's good to confirm.

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Richard Kaye
  Rick Strahl
  Feb 21, 2025 @ 05:13am

Looks like it's working as expected for me with the experimental release. Thanks!

Gravatar is a globally recognized avatar based on your email address. re: Odd session cookie reset
  Russell Campbell
  Rick Strahl
  Mar 20, 2025 @ 04:00pm

Whew, lots to read. I'm using WWWC 7.35. I have the session initialized in OnProcessInit. Right now, for testing, I have it set to 30 seconds. I'm hitting a page and it sees that the session has timed out and lets me log in. I get logged in and I hit the page every few seconds (far less than 30). It's using the session to get a var to see who the user is and so this should - as I understand it - reset the timeout. I'm expecting it to not timeout because I'm reloading the page every few seconds. If I were to keep doing that for 5 minutes or 5 hours, I'd expect it to not time out. But, if I pause for 30+ seconds with no hits, I'm expecting to need to log in again. But what seems to be happening is that the session times out after 30 seconds regardless of my intervening hits. Is this related to the bug you mentioned, Rick? Or am I just misunderstanding how it works, meaning does it just timeout after X seconds regardless of any hits coming in from the same browser session?

© 1996-2025