Turning Bubble User Auth into a Session Container

Developing an internal tool that uses Google/MSFT SSO for login raises a tricky security question: what happens if a user’s external account is compromised? If someone gains access to their Microsoft or Google account, they can log straight into our Bubble app through SSO and immediately access everything the real user can. Bubble’s SSO action runs entirely client-side, so any post-login checks we try to run (IP, device, location, language, browser, etc.) are technically bypassable. We also can’t reliably distinguish between a real user and an attacker if both sign in at the same time, because Bubble ties authentication to the User object as a whole rather than to individual sessions.

A possible approach is to stop treating Bubble’s built-in User as the true account and instead treat it as a session container. Bubble creates or finds a User based on the email provided by the SSO provider. If we separate this from a separate RealUser data type (the actual internal account), we can apply RLS and privacy rules on a per-session basis rather than at the global user level.

The workflow becomes: the user logs in via SSO, but the resulting Bubble User is not immediately linked to their RealUser record. A backend workflow (or manual process) evaluates the login and decides whether to link this session to the RealUser. Once linked, the workflow also mutates the Bubble User’s email to a random UUID so that future SSO logins always generate a new Bubble User, which must undergo the same verification. RLS conditions then reference the RealUser field, so only sessions that have been explicitly approved gain access to internal data.

In effect, Bubble’s native authentication becomes session-based rather than account-based, giving you a way to evaluate and approve each SSO login independently while protecting the underlying RealUser data.

2 Likes

A simpler setup would be to keep the Bubble user as is, then have role-based privacy rules, and roles accessible for the session via “escalation of privilege” i.e. the additional gates/checks you are thinking of.

Unless there is a specific vulnerability of the Bubble user?

2 Likes

The problem with role based privacy rules is that they’re global. Privacy rules cannot reference any client side information, only the database. Therefore the entire user account can only be valid, or not. If the real user is online and valid, then all instances of this user are also valid by default. There’s no way for privacy rules to be session specific.

Also, any login instance of an existing user would be valid by default. It’s only by client-side checks that a flag may be thrown. As there’s no database trigger that can be initiated by a login, all must be client-side initiated. These client-side checks can be bypassed.

Any new login needs no access by default, with the checks then allowing access.

The risk of this is obviously slim, but not zero.

1 Like

Sound objections, unfortunately!

One more idea … there is an option to read if the current user has activated 2FA. I forget if 2FA is applied instead of, or in addition to, the auth given by SSO.

Could make 2FA a policy and only give a role if 2FA is activated?

1 Like

The same is true of username and password. It’s self evident that if a user has the credentials they can get in.

With that said, part of the reason to use SSO is that it offloads the burden of responsibility for account protection to the SSO provider, which will generally have auth and pretty complex systems to detect malicious logins. So, it is perfect? No, but it’s likely better than username/password/magic link authentication

Correct Google/MSFT Auth is pretty good, and thats why I’ve put most the login burden on them rather than a separate system our staff have to remember.

However, it’s not perfect. The user still is the weak link and popularity results in these accounts being targeted more. We have 2FA enforced on all our staff accounts, yet they’ve been hijacked over before. Emails from ‘rnicrosoft.com’ (articles online about this), phishing emails from valid clients’ accounts that have been taken over, invoices with changed bank details. The list goes on :joy:.

Hence the desire to have an extra step if the account is compromised.

We don’t have a huge number of staff with high-privilege accounts that can do damage, so manual acceptance per device/session could work. Wondering if anyones done similar before.

1 Like

Feel free to ask any further questions if it doesnt make any sense to you! This is an internal app that 30 odd staff will be using all day everyday. If we must approve every possible damaging action these would essentially be all actions and thousands per day. The app would be useless.

If the user’s roll enables access to create/update/delete they should be able to do so, as long as their current session has been validated.

I am all ears on another neat way to prevent a compromised account from having unlimited access. Approving every action on the app isn’t one of them :frowning:

Can add a table for “valid session” to the database. When privilege escalation is requested, client-side passes to server the id from document.cookie . If the checks pass, store as a valid session.

The painful part is including the session id as a constraint in every protected search. Your realUser approach might be simpler.

It doesn’t matter if a server-side check is requested client-side, the check itself can take place on the server with data supplied by the client.

Yes this is a good idea, but every action i would have to turn into an api call. If i had to do this i’d move to Xano or similar back end, which would allow more flexibility around Auth.

Yes thats right, but the workflow has to initiate from the front end (which can be stopped). If the account is valid by default, then stopping the workflow prevents the inaccess. If the account is invalid by default, then stopping the workflow prevents the access. This is the crux of the issue essentially. This and being able to separate user ‘sessions’ in the privacy rules :grimacing:

I tried it out in a test app, JS reading document.cookie or cookieStore only finds the user id. The cookie with session id is not available to JS even though it is visible in browser dev tools.

Thanks for helping me explore that fantasy :cry:

Found the topic interesting and I’m just trying to understand your use case scenarios. A couple of questions come to mind:

  1. If it’s an internal tool why do you need mixed SSO providers? I’d think that an organization would enforce the use of one or another, Google or MS
  2. If you need such strict security, why not use layers like Cloudflare WAF or Zero-Trust?

Overall, it feels like you’re trying to over engineer a solution.

1 Like

Actually we don’t need Bubble’s session id. For this purpose all we need is a server-generated string that is hard to guess, I’ll call it my-session-id.

The page workflow “User is logged in” can look for my-session-id in browser local storage, if not found can call API backend via API connector to assign one pending checks.

Then sensitive data retrieval looks like:

It doesn’t matter if a malicious user borks their own method of access.

1 Like