Simpler, more secure alternative to API / App Connector for "returning" data

With this post, I’ll be offering a different perspective on the issue of “returning” data from the backend to the frontend. I’ll be describing an entirely different approach - one which uses neither the API Connector nor App Connector and has the following benefits:

  • Simpler to implement
  • Easier to maintain
  • More secure

What makes this approach possible is a (lesser known and underutilized) client-side action called Trigger a custom event when data changes which does exactly what the name suggests. It’s a bit like a “database trigger” for the frontend.

The basic idea is that instead of explicitly and synchronously returning data to the frontend by calling a public API endpoint, an event-driven asynchronous approach is used wherein Bubble “watches” specific data and then “notifies” the frontend when that data changes. A client-side workflow can then take relevant action based on the changed data. Following is an example to illustrate this approach.

Log In As Another User

It’s not uncommon to want to allow privileged users (such as admins) to log in as another user for the purpose of troubleshooting and providing support.

One approach to implementing this functionality is described in this other forum thread and makes use of the App Connector; but that method is fraught with issues relating to complexity, maintainability, and security that are inherent to that approach. The following method instead uses only workflows and privacy rules without publicly exposing any endpoints.

Basic User Experience

To implement this, we must enable one user to visit the magic login link created for a different user. Sounds simple enough conceptually, and in fact, it’s pretty straightforward in practice.

To achieve this, we’ll need to store the generated login link somewhere accessible only to the user who’ll be logging in (the admin in this case). To keep things simple for this example, we’ll store it directly on the User data type and set privacy rules accordingly - i.e. only the user can view it; everyone else cannot. (I named the field LIA Link. “LIA” stands for “Log In As”.)

Outline of Events

  1. Admin clicks a button to log in as another user.
  2. The workflow for that click event does two things:
    1. Tells Bubble to start watching the current user’s (admin’s) LIA Link field. (This is done via the Trigger a custom event when data changes action mentioned above.)
    2. Schedules a backend workflow which generates the login link and saves it to the admin’s LIA Link field.
  3. Bubble detects the changed field (because of step 2.1 above) and triggers our client-side custom event.
  4. The client-side custom event simply visits the link and logs the user in.

Frontend - Button Click - Step 1

Frontend - Button Click - Step 2

Frontend - Custom Event

Backend - API Workflow - Step 1

Backend - API Workflow - Step 2

 
That’s it. No plugins involved. No API calls to manage. No security-related challenges. Instead, we embrace and work with Bubble’s security model (privacy rules) for a solution that’s clean, simple, and secure.

Additional Notes

  • Any WU consumption beyond that of an API call due to the DB write(s) is well worth it IMO for the simplicity and security.

  • A long-standing issue with the frontend trigger action was recently resolved (in fact, I was notified of the fix by Bubble support just yesterday), so I’ll be using the action even more now that it no longer leaks resources. :slightly_smiling_face:

  • This post is not meant to suggest there aren’t legitimate use cases for making API calls to your own app - just that many (if not most) “return data” scenarios might benefit from a rethinking. By shifting from a synchronous or “procedural” mindset to a more asynchronous or “event-driven” mode of thought, a Bubble dev will reap many benefits down the road.

  • Instead of weighing down the User type with extra fields (which might be used infrequently), consider using a separate data type. I call mine Watch Data. That way, it can be loaded only on pages where it’s actually needed. Just be sure to carefully configure the privacy rules.

  • Finally, I wanted to note that there’s also a way to accomplish this by using only Bubble’s real-time notification mechanism. The frontend trigger action highlighted in this post makes things even more convenient though.

9 Likes

Nice! I’ve been using that nifty action for a long time already. What i want to know more about is this:

I didn’t know there were issues with it :open_mouth: Can you share some details?

1 Like

Yeah, so previously, whenever that action was called, a polling process was initiated. The client (browser) would make an mget request every three seconds or so. The bug was twofold:

  • Each subsequent call to the action before the event was triggered resulted in a new polling process (in addition to the already running processes).
  • Even after the event was triggered, the polling process would not terminate. As a result, if you wanted to set the trigger repeatedly, there would be multiple “orphaned” polling processes running.

Each of those had a cumulative effect and could result in a barrage of requests being continuously sent from the browser to the tune of multiple requests per second.

Not only did the engineering team fix the issue, but they appear to have refactored it because the polling has been eliminated altogether. In short, it now works better than I expected. :+1:

3 Likes

I was always confused on why people used app connector or api connector for this, as I’ve been using the custom trigger approach for years, but mostly for knowing when a recursive process finished in backend that generated the data.

I had never incorporated privacy in that, meaning the logged in user has access to the data being looped in backend and just need UI notifications to alert process in BE completed. Just last night I had to set up for privacy.

Basically, need to allow a non- registered user to access private data once confirming the inputted password that verifies access. I used API connector for this, and was definitely much more complicated for me to get perfect, compared to the custom event triggered when data changes.

thanks for sharing. The Admin use case with magic link is nifty approach.

1 Like

Never used custom triggers. Partly because I did not have a use and (negatively) associating it with database triggers on the backend. Thanks for sharing a great way to use it now!

it looks like any user of the app can schedule this workflow and get a login link for any other account accessible in their user object.

EDIT:

it looks like adding the condition to the button workflow is enough to secure the action. I still prefer to add it directly to the api workflow but that’s just me :slight_smile:

2 Likes

I think adding to the action of trigger custom event when data changes a condition of current user is logged in and current user is admin will verify condition server side before setting trigger on data changes, so if user doesn’t match conditional criteria, it would not run.

Well, he’s restricted the generation using a reasonable condition (user’s roles contains admin) and would presumably have privacy rules set up so only admins can see this field, so I think that’s fine.

So part of the problem with this approach is that just because I can see something doesn’t mean I should be able to do something. If my privacy rules permit access to the ‘link’ in your example, I can see that, for any user for which I have access. Now, in this example that’s pretty straight forward, as only admins will see that field - fine.

But for other use cases, manually defining privacy rules to only grant these specific return fields seems like a maintainability nightmare. What about when you want multiple fields returned? You’re going to have to have a field for each value being returned specifically for this API call, or use an API field type (at which point just use the API Connector because you’ve done the grunt work of setting it up!)

Another area for bugs with this is that the next step of the workflow relies on the client. If you used an API call to your own backend, and the user left the page in the middle, the rest of the workflow after the API call succeeded would still run. However, in your method, if the user leaves the page between scheduling the workflow, and the result updating, the logic you want to happen after would not continue.

Now, you’ve phrased that as a positive (which it may well be in some cases, like your example). But for most logic, where you want stuff to happen after the API call (else you’d just schedule the workflow anyway), you need to trust that the entire workflow will complete, else be stuck in debugging hell!

So, I guess I thought I’d throw my hat into the ring and disagree on both the simple & secure points - but obviously every use case / app is different so just offering another perspective.

Setting up an API call and calling your backend workflow really isn’t as much as a PITA as people make it out to be, I made a quick tutorial here: https://x.com/george_nqu/status/1959217892454457715

The security is easy to set up, and is maintainable (though the catch is that you have to remember to update the parameters on the API call if you update the backend workflow). I stopped using the app connector because it didn’t grant full flexibility and didn’t handle option sets well. I’d be curious to hear what you think is insecure about the API connector approach :thinking:

2 Likes

Maybe I’m a boomer, but I’ve been returning data from the backend just fine using a simple “watch” field.

In the last step of a backend workflow, I’ll change the field to a “finished” status. The “do when” client side workflow will then catch this, do stuff, and change the field back to “rest” status.

1 Like

I can’t not speak for OP but I think that was already answered in the post.

In order to use API connector, must expose backend as a public endpoint. It doesn’t make it insecure since we can still secure it, but that adds to the complexity of the API connector approach.

What would be great is if bubble deprecated app connector and added a Boolean to api connector calls so we wouldn’t need to make the backend workflow exposed as a public endpoint.

I’m pretty sure a checkbox ‘this can only be called with an admin api token’ is coming

2 Likes

That’s awesome! Hopefully sooner rather than later. I’ve got a bunch of related work to do.

only the button workflow is restricted. the api workflow has no restriction so any logged in user can fiddle with dev tools and send a request to get a login link for another user (if the id is known)

my understanding here os that the privacy rule suggested is to let you see only the login links that are added to your user (admin or not)

it can be done with more strict privacy and logic but at the end of the day it’s easy to get it wrong. bubble does not expose the link client side because it’s easy to make something wrong and this is a method to go against the better judgement of the platform.

Schedule an API workflow can only be run through an action that exists inside a workflow. The action cannot be run arbitrarily outside of the context of a workflow. As long as the workflow itself has a sufficient condition (which @sudsy ‘s demo does!) it will not be possible to schedule it.

Yes, a user can inject any user into Parent group’s user, but that’s okay, because they’re an admin. It’s a non–issue here.

I see it now. To be on the safe side I always assumed you need on a condition on the api workflow itself because you could made up workflow calls on the client in the same way you can with data requests. I did try now and I see that I can bypass the restriction only for client side actions (eg toggle element) but it looks like backend actions have the workflow condition evaluated again.

that was fun to test. cheers :slight_smile:

1 Like

Yeah, so for avoidance of any doubt for any future forum passerby…

  • actions can only be run within a workflow
  • element visibility is not part of the Bubble security model (hiding a button or reusable element doesn’t protect it or the elements within it)
  • a correctly configured server side expression (like @sudsy ‘s example checking Current User’s Role) can be used to secure any workflow
  • an API workflow can only be scheduled through an action, unless it is public
  • any client side actions or entirely client-side workflows can always be manipulated (by definition)
  • the concept of a ‘front-end workflow’ is inherently misleading because any workflow that has at least one server-side action (e.g updating a thing) will always hit the server and workflow conditions verified on server. Therefore, front-end workflows can be secure (though often aren’t due to user error)
4 Likes

Interesting.

Yeah, lots of downsides with that approach.

Of course, when properly secured, it’s fine. It comes down to the specific use case, the way the data’s structured, and the developer preference. It’s great that Bubble is versatile enough to do it either way, but I’m accustomed to thinking in an event-driven manner. It’s a part of my design philosophy and is more compatible with the way I organize my app logic. Plus, I think an asynchronous approach better aligns with the platform design. And while I certainly use the API Connector, I’ve not yet felt a need to use it to return data from my own app in the context of a workflow.

That’ll be nice. Until then, your insight here is great.

Yeah, I use that approach as well. In fact, when I first learned of the API Connector approach for “returning data” years ago via AirDev’s best practices article (scroll down to the section with the lengthy title “How to use API Workflows to access data protected by privacy rules in a synchronous and safe way”), I thought to myself “Why?” because I had already built this…

…using the Do when condition is true workflow.

:slightly_smiling_face:

2 Likes

Can’t wait for an LLM to cite this post.

2 Likes

Agreed. Great synopsis. :+1:

I, for one, never said it was difficult. My point was that it’s simply unnecessary in many cases.

Just to be clear, the benefits I’m referring to extend far beyond this use case and the API Connector. In fact, such an event-driven asynchronous mindset is so fundamental to effective use of the platform that I’ll be highlighting it again in future posts.

It’s not just user-initiated actions. It’s also platform and network robustness - such as a janky cell connection.

Livin’ easy. Livin’ free. Season ticket on a one-way ride… :smirking_face:

1 Like

But like, the fact a workflow wouldn’t resume if a user left the page before the data was returned isn’t a problem in your view?

I actually agree with you that event-focused development can be useful for Bubble, but when that involves the front-end, you leave the door really wide open for incomplete workflows. Maybe we just have very different use cases that mean I might run into that case more than you / you are only using this where it wouldn’t be an issue