Hooks from authenticated pages that contain an empty user object

Posting this topic for Chris Barber:

As noted before, we consistently get hooks from authenticated pages that contain an empty user object. This has been happening since we first deployed, last summer. We have logged >3900 instances of this since then. I’ll paste an example below. We get them randomly throughout the day. This results in our app not knowing what user sent the hook, and it’s been a consistent source of customer experience problems. For example, we get a hook saying that there was a successful payment, but the user information is omitted. Can you help us?{
"commonHookSetName": "app",
"data":
{
"devDataEnabled": false,
"form":
{
"hookSetName": "aForm"
},
"hookPackage":
{
"action": "runUtilityHook",
"options":
{
"medplanSuccess": true,
"path": "pay",
"type": "restoreState"
}
},
"id": "FR_409E0BCC-61B9-5742-AF45-8A37C21865AE",
"idOrganization": "OR_962C0C2A-4081-F646-B459-B2CA91FA104C",
"idOwner": "",
"isPublicExample": 0,
"model":
{
"appData":
{},
"returnToPortalDisabled": true,
"showPayButton": false,
"vars":
{
"portalButtonText": "Working..."
}
},
"query":
{},
"state":
{
"domain": " portal.adhdonline.com ",
"host": " portal.adhdonline.com ",
"params":
{
"handshake":
{
"address": "::ffff:10.42.2.0",
"headers":
{
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9",
"cache-control": "no-cache",
"connection": "upgrade",
"cookie": "_ga=GA1.2.159739716.1616161045; _fbp=fb.1.1616161045749.2038246402; __zlcmid=13BjtLDF8JUFHyZ; _ce.s=v~e7b72f8fcbac81d0a2dd461c1c7ad245543a0efc~vv~6~ir~1; _gcl_au=1.1.1065442700.1624251357; __stripe_mid=a4ce307e-9550-4a56-848b-c54bc86b2d20086108; _uetvid=f7f10be0d24c11eba566997e7ced4dea",
"host": " portal.adhdonline.com ",
"origin": " https://portal.adhdonline.com ",
"pragma": "no-cache",
"sec-websocket-extensions": "permessage-deflate; client_max_window_bits",
"sec-websocket-key": "6jlwdqaE7BySV/HhxMJ+Xg==",
"sec-websocket-version": "13",
"upgrade": "websocket",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
"x-forwarded-for": "92.119.177.22",
"x-forwarded-host": " portal.adhdonline.com ",
"x-forwarded-port": "443",
"x-forwarded-proto": "https",
"x-original-uri": "/socket.io/?EIO=3&transport=websocket",
"x-real-ip": "92.119.177.22",
"x-request-id": "b1d39339018ad66a4241280775031558",
"x-scheme": "https"
},
"issued": 1624882714582,
"secure": false,
"xdomain": true
},
"host": " portal.adhdonline.com ",
"idLog": 991,
"provider": "socketio",
"query":
{}
},
"server":
{
"dc": "AWS-US-WEST-1",
"gateway": "XML",
"version": "0.10.1"
},
"subdomain": "portal"
},
"user":
{}
},
"hookName": "onUtility",
"service": "formsService.onUtility"
} (edited)

This is on authenticated pages and our logs show this has occurred plenty of times just moments after a prior hook call from that user was successful so there shouldn’t be any issues of things expiring, or, if things had expired, shouldn’t for the user be required to re-authenticate for security? (we store the user id in model.vars, that’s how we know).

What I pasted above is the payload we receive from Better Forms. Charles, you said that “using a single hook for all pages is NOT recommended as a design pattern…”

How would our scripting and reuse of a scoped hook across several pages have anything to do with better forms sending an empty user object on an authenticated page? As you suggested, we have checked $$bf_user and in these cases it is empty, as that variable is derived from the payload, and as the above shows, the user object is empty in the payload.

The user id randomly shows up in subsequent hook calls. Say we get five hook calls from an authenticated user on an authenticated page in a period of 10 minutes once in a while one of those will have an empty user object. One will have the user object, the next won’t, the next will, all within a short period of time, for example.

Here are my questions:

  1. What is intended behavior? Should we always expect the user object to be sent on hooks on authenticated pages?

(2) If a user’s authentication/authorization expires (e.g. they have had the browser open for X period of time) and they click a button that calls a hook, will you force them to login again, or do you automatically re-authenticate / re-authorize them? What is the X period of time by the way?
There isn’t documentation that covers this so we are left to guess, and that’s been one of the challenges.

1 Like
  1. Currently a utility hook does NOT require auth, although the onFormRequest hook does. This is intentional. If a page is to return data based on a user, then you should always check for that hooks user.
    If you are seeing utility hooks run with no auth object there could be several explanations so it’s hard to diagnose.
  • Does the client ( browser) show the same? ( is it from the same browser tab etc)
  • Is the scope of the hook the same for the un-auth’d call as the auth’d one? This will be hard to tell if you are using the same hookset for all calls as noted above.
  • Are there any other discernible differences in the calls? ( can’t tell from the single post above)
  1. If the users JWT expires then they will be redirected to the login page if an auth challenge happens. This will happen when the users tries to navigate to a different page or refresh the same page that requires auth. Currently it will not happen if a util hook is run.

The behaviour of #2 could be changed but as it stands can be a breaking change for many users that have pages that need both auth and no auth so I suspect would need a switch setting in the page editor.

HTH

Hi Charles,

On question 1:
Under what conditions, if any, is it expected behavior that a utility hook on an authenticated page will be sent without the user object?

Are you saying that this will happen if the JWT has expired by the time the hook is fired?

On question 2:
What would cause the JWT to expire? If it’s time, what is the amount of time?

Thank you.

The JWT is issued once a user is authenticated.
If it has expired or if it deleted ( clearing browser etc) then it will not get sent because it does not exist.

The token expires 24Hr after last use.

Thanks. So, putting this together, you are saying JWTs expire 24hrs after last use (or they can be deleted).

We are seeing utility hooks sent on authenticated pages with no user object just minutes after that same user sent a utility hook from another authenticated page. Assuming the user didn’t clear their browser in that time, how could that be possible?

As noted in the first post, I would first inspect the client ( browser identity, IP, clientID etc of the calls to make sure they are coming from the exact same source.

That is how we would have to determine if it was indeed an issue.
To our knowledge, no one has reported this to date, but that does not mean it is not an issue either.

c

Follow up on this,
If for some reason the JWT expires, gets removed etc then the hook can run as noted above.

We will look at the possibility of adding a flag in the IDE that prevents hooks from running without authentication.