Forum Academy Marketplace Showcase Pricing Features

Any ways to handle user authentication outside of Bubble?

Do you know of any good ways to handle user authentication outside of Bubble for a Bubble app? If so, what’s this look like tech-wise?

Also, any good way to have users move their credentials over without having everyone need to create a new password?

We need to support custom subdomains for our app but Bubble doesn’t offer a viable solution for this, so we’re looking to move user authentication out of Bubble which would likely enable us to solve the custom subdomain challenge.

3 Likes

We’re utilizing Passbase for identity verification. We’re able to use a link in a button that transfers them over to it, then we are notified and manually approve their profile on our platform. With a bit of custom API, it can be automatic.

We also use social verification via sign-in (Facebook, Linkedin) and phone verification (Twilio).

Is that what you’re looking for?

Thanks @alex.p. How does Bubble know a user signed in with Passbase? Are you logging them into Bubble using a temporary password or is there another method?

They create an account prior but must be verified in order to do certain things. Right now, we have to manually change that verification when passbase verifies them. It requires an API connection to do it automatically, which we don’t have the manpower for atm.

Got it. Thanks Alex.

I believe we’d need to be able to have people register and log-in using a 3rd party system to get around our current challenges with bubble’s domain constraints.

Social sign-in might work, in theory, but many of our users require email/password as an option so social sign-in alone wouldn’t work for us.

Good ideas here. Thanks.

@sridharan.s, ultimately, I think the solution here is to get Bubble to solve whatever it is that represents the “subdomain problem” (by which I take it to mean you don’t have direct access to rules on the web server?).

That being said: Things to think about are the fact that Bubble users can (out of the box) authenticate with either an email/password combination AND/OR via external Oauth 2 credentials. And a user that signs up with Oauth 2 does not have a password – unless you later allow them to create an email/password pair while logged in. (In fact, there’s a read-only system variable for this: User’s uses password (which will only be true if the user uses the email/password login combo… if the User has exclusively Oauth 2 access to your app, this value will resolve to no).

I’ve kind of wondered to myself whether one could implement passwordless and Oauth-less authentication to a Bubble app. (That is, implement the “one-time password” system used in some places where “logging in” involves submitting your email address and then receiving a one-time use password via clicking a link.) It kind of seems like this would be possible, though I’ve not tried hard to implement it.

On the face of it, it seems to me that we are a few pellets shy of a full load on this one. We either need an API to the login system (i.e., be able to build plugins that allow us to trigger the state of being logged in) or an API to the password system (i.e., be able to set the user’s password to some value – not just “reset” the password) to be able to do this.

But I do wonder if perhaps one could create an external API (or even do it via the POST API workflow of one’s app) that impersonates an Oauth 2 API and, thereby, provides credentials that are NOT Oauth 2 but are in fact some other secure-ish system.

Anyway, there’s nothing inherently “connected” about user authentication and custom subdomains. And it seems to me that – rather than hacking about which will surely lead to security issues – one should just design and press for the solution that one needs with the engineering team at Bubble.

Now, of course, Bubble may not be able to accommodate such solutions on the shared clusters. But it would seem eminently doable on a dedicated cluster.

AND, all of that being said, I’d be very interested to understand how in-browser authentication works in Bubble as I don’t quite grok how it works. (And the reason that I don’t is that we don’t have a programmable API to those features.)

This is the sort of thing we’d need a Bubble person to chime in on, really.

And while this subject is of academic interest to me there are many more features that I’d rather have (e.g., a GET method for API workflows – which, seriously, is an afternoon of work to fix) than some interface to the password system and/or support for user subdomains (but also that doesn’t seem like much work to add, either).

I kinda had the impression that the app you’re talking about was on a dedicated system, anyway. Isn’t this request a professional services engagement type thing for you rather than a hail-mary pass for assistance from the peanut gallery? :wink:

You can use @ZeroqodeSupport’s firebase plugin to authenticate a user. From there you can connect to your database from multiple apps in real-time without worrying about scalability.

I have actually tested out a system like that. I use a lot of external apis in AWS and looked at ways to create unique tokens on the fly to make authentication and authorization easy on the receiving end.

It doesn’t fit the use case discussed here, but might be an inspiration for others. In short, wrote a small serverside plugin with crypto (vanilla-node, so no dependancies).

The plugin takes whatever string or array I throw at it, and creates a encrypted token with aes-256-ctr. The tokens contains an iv cipher, so if I encrypt the same string twice, each token will be unique.


The token is then decrypted on the other end, and the values can be used in conjunction with the standard parameter values.

Compared to JWT this is much more secure as the token can’t be read, but because iv ciphering uses a random buffer, each encrypted string will be unique although the data doesn’t change. For the same reason, the auth token in the recipient api cant be cached, so there is some added latency.

I’m still hesitating to implement this live as each api call takes 500-1000 ms longer.

3 Likes

Thanks @Keith. We’re on dedicated. Spending something like $2k a month right now.

Nonetheless, Bubble won’t even offer this on a sponsorship basis - Emmanuel said they’ll revisit it in 6 months. He also claims only 1 other person has ever asked for a solution to this when there are more than that in the forum in the last 48 hours.

I’m still pushing this with the Bubble team, of course, because Bubble building support for this seems like the obvious answer, but I don’t have high hopes anymore.

I appreciate the ideas, everyone. We’re going to look into each of these.

2 Likes

You’re welcome. From a user experience side, we find people want to do as little as possible prior to signing on, which is why we separate the steps.

Wow, super great info here, @simon7! Really interesting.

That’s a drag that the Bubble team doesn’t have cycles to address to your issues, @sridharan.s. As for routing, even just a little bit of scriptability at the web server layer would go a long way.

Playing with this solution. Anyway to move existing bubble user creds to firebase so that auth is all in one spot?

Have you looked at Auth0?

@NigelG has done some work with it and might be able to answer some questions

We’re doing this with Auth0 and the Auth0 plugin (it costs $50). It works by redirecting to your Auth0 subdomain to login, and redirects back to bubble with the token in the url. The plugin then logs the user into bubble (creating a user if it does not exist). You can also include other details to be send back in the token if you want to store a user_id, email, or whatever.

I also store the access token and submit it external API requests.

@byron_bubble - is the transition fast such that your users barely notice their redirected?

It redirects first to another auth0-hosted page where they actually login. From here, it takes them back to bubble. So it’s not really a matter of transition-speed, if you know what I mean

Hi,
I am also using auth0, however I do not use the $50 plugin. Auth0 provides a free redirection page which works just fine. But since I wanted to remove any trace to auth0 for security reasons, I created and API to my backend (Backendless), who would request a 2FA/passwordless login via mail, managed by auth0. If succeeded, my backend would save the access token and send it Bubble for further use of the tool.

So: Bubble --> backendless --> auth0 --> authentication mail to user --> auth0 --> backendless --> Bubble.

Seems like a hassle, but security is an important principle to me. I am aiming for a zero knowledge system. Not sure if this is possible with Bubble though

2 Likes

Can you please elaborate about your approach. I find it useful for my application. I will mark my questions.

Q1. Where is your application creating the AES encryptedValue? You mentioned it is hosted on a node server. Is it hosted on bubble? or is it hosted on AWS?

I am assuming it is hosted on AWS. As per my understanding, you have the Node API open and you pass the API email, id, url and isDevApp fields and it would give you a encrypted token. You use some kind of initial vector which you termed as “iv cipher”. From what I know you would need this initial vector to be given to the decrypting party.
Q2. Do you return IV and encrypted token from the Encryption service and pass it to the decryption service?

Hi @anthony.lyon,
So first a “warning”; i’m no security expert so if its secure in a production or not you need to investigate yourself. The inspiration is from JWT, but the way the code below works is that the whole package is randomly encrypted and used in your post/get request to your api in Azure/AWS or whatever. The upside is that you can send secure data encrypted, whereas a JWT (although https is secure and all) can be read be anybody if it is picked up. JWT also holds an encrypted value, but that value is only used to verify that the content has not been changed. The downside is that each request will be unique. That means that you receiving api cant do any caching, as it needs to decrypt and verify every single request. With JWT you would typically set a TTL so that requests every 5 or 10 minutes are checked.

So first of you need to write a plugin in bubble. I could release the plugin I already have built, but for the reason stated above im not going to. If you feel like the solution is secure, please feel free to use it however you want.

I would probably write it a bit different today, but the setup looks like this:


Now, as said this plugin only creates a string. On the receiving end you need to decrypt
the string using the reverse method. In the screenshot you can see exactly how this is setup in bubble.

A full code that first encrypts and then decrypts a key value pair can be found below (the decrypt part is to be used in you api). Its also in the decrypt part that you’d want to reject any requests if the server cant decrypt the value.

const YOUR_SECURE_STRING = "b2df428b9929d3ace7c598bbf4e496b2";

const crypto = require("crypto");

const algorithm = "aes-256-ctr";
const key = YOUR_SECURE_STRING;
const inputEncoding = "utf8";
const outputEncoding = "hex";

function encryptIv(payload, key) {
  const iv = new Buffer.from(crypto.randomBytes(16));
  const cipher = crypto.createCipheriv(algorithm, key, iv);
  let crypted = cipher.update(payload, inputEncoding, outputEncoding);
  crypted += cipher.final(outputEncoding);
  return `${iv.toString("hex")}:${crypted.toString()}`;
}

function decryptIv(payload, key) {
  const textParts = payload.split(":");
  const IV = new Buffer.from(textParts.shift(), outputEncoding);
  const encryptedText = new Buffer.from(textParts.join(":"), outputEncoding);
  const decipher = crypto.createDecipheriv(algorithm, key, IV);
  let decrypted = decipher.update(encryptedText, outputEncoding, inputEncoding);
  decrypted += decipher.final(inputEncoding);
  return decrypted.toString();
}

let payloadArr = [
  { key: "id", value: "12345x54321" },
  { key: "email", value: "[email protected]" },
];
let payload = JSON.stringify(payloadArr);

let encryptedData = encryptIv(payload, key);
let decryptedData = decryptIv(encryptedData, key);

console.log(encryptedData);
console.log(decryptedData);

Hope all of this makes sense.