The built-in User Type enables your app to handle user authentication. A user is uniquely defined by its email, or its ID if the user is authenticating through an external service (such as Facebook OAuth).
Our Academy course for your first app includes how to build a signup system
A user isn't created through a 'Create a new thing action', but instead through the 'Sign the user up' or the 'Create an account for someone else' action. Going through such an action in a workflow (in Run-mode), will create a new thing of type 'User', and will validate the uniqueness of the email.
If the user goes through a 'Sign the user up' action, the user will be able to enter a password, while if you use a 'Create an account for someone else', the user will be marked as 'temporary password' and will be prompted to modify his password if you have defined the relevant parameter in the Settings tab. This setting lets you pick a page to redirect users that haven't entered their own password yet and lets you built a form (with the associated workflows) that let users define their own password. Redirection happens on page load and not after 'Log the user in' action.
Note that once a user has been deleted through a 'delete thing' action, this user will not exist in the database any more, and will not be able to log in, etc.
One of the most important data sources you can use is the 'Current user'. This describes the user that is currently using the application (versus another user in the database). A session is what describes the concept of a user using the application at a given time. Technically, a session is defined by some cookies at the browser level. Depending on your app settings, you can set an expiration on these cookies. In general, such cookies are infinite, and therefore a user will be in the same session until they log out, or clear cookies (similarly to Facebook, you are logged in permanently until you log out or use a different browser). Depending on the situation, the current user can be a signed up or temporary.
If a user has signed up to Bubble (with an email and a password), a permanent entry is created in the database using this email and password. When a user opens your app in a new browser (without cookies) and enters their credentials through a login workflow, they will be logged in. The value of 'Current user is logged in' will return yes. If you modify the current user, this will be saved permanently on the database object, and if the user logs in on another device, they will have the changes applied to their account.
One important consequence of this is that all users that can be found through searches in the database will be marked as 'logged in' on the server, as they are permanent accounts.
As soon as a Bubble app is opened in a browser, a user session is created. If a user already logged in and hasn't cleared cookies, the session will be using the same user as before, but in the case of a fresh session (without a logged in user), a temporary user will be created. This user will be marked as 'not logged in' (in other words, 'Current user isn't logged in' will return yes).
The temporary user behaves like a signed up user, in the sense that you can modify it, and it will be saved to the application database. If a user comes back using the same browser and hasn't cleared the cookies, any value that you have used to modify a field on the user will be the same. Bubble automatically clears temporary user data though. After three days, such a user will be deleted, and when a user opens a session in the same browser, a new temporary user will be created, for three days.
When a user first visits an application, they will be seen as a temporary user. If they go through a sign up workflow, the current, temporary user will become a signed up user and will be saved permanently in the database. This has some important consequences in terms of workflow design. Imagine you have a workflow that asks a user for their age before they sign up, and save it to the 'Current user'. If the user effectively signs up within three days, the permanent user that will be created then will have that 'age'.
The most common way to authenticate users is to prompt them to enter a password or an email. However, very often, you will be using some external services to authenticate users using their credentials from another service. This is done through plugins. Doing so has a few advantages when you design your app. We'll use Facebook as an example below (in other words, your app offers a button 'Login with Facebook'.).
- This lets your users authenticate faster into your app, and they don't need to remember another password. Usually, most services offer a straightforward, one-click authorization flow to authorize an app to use their identity with them. For instance, you will need one button 'Login with Facebook', and the user will be prompted by Facebook to authorize your app to use their credentials.
- This also lets you make some calls to the service on behalf of the user. With Facebook, this lets you fetch their email (registered with Facebook), get their profile pictures, post on their wall, etc.
When you set up such a flow in Bubble, you will need to define the level of authorization you want from your users for your app to function. By default, most services only expose the public profile and the email when users sign up on a third party application using their credentials, but you can ask for more permissions (for instance, post on their wall). Note that you should only use social logins and ask for permissions if you need them. Asking for permissions to access some data is something that users are sensitive to, and can lead to fewer sign ups.
When a user signs up with a social network (Facebook) in Bubble, a new user is created in the database, similarly to a traditional sign up flow with email and password. The main difference is that the way to login for the user, once logged out, will not be by entering their password (since their didn't define one), but by logging in with Facebook. If a user is logged in with Facebook in a browser, and if your app uses Facebook login, the user is automatically logged in as the current Facebook user.
Users in Bubble can use traditional logins and social logins at the same time. There are a few cases here.
- 1.If the user is currently logged in with email and password, you can prompt them to link their account with an Oauth provider (such as Facebook, Google ...). If a user goes through such a flow, a new user will not be created, but, instead, the Oauth credentials will be added to the current, logged-in user. After this flow completes, the user will be able to login either with his email/password, or via an Oauth flow. If another user exists in the database with the email provided by the external service, the action will fail and a message will be shown to the user.
- 2.If the user isn't logged in when he goes through an Oauth flow, a new user will be created, except if a user with the same email (the email registered with Facebook) already exists in the app's database. In such a case, the workflow will fail and a message will be shown to the user.
- 3.If a user has signed up with an external service and wishes to add a password to his account, they can do this by going through a 'reset the user's password' action. This will effectively modify the user that was authenticating only with Oauth credentials and will the email and password values to the user object.
Bubble apps can be used as an authentication provider for external services or applications, similarly to the "Log in with Facebook" feature seen in many apps and websites.
- When your Bubble app is used as an OAuth provider, a GET call is made to https://[Your-App-URL]/version-test/api/1.1/oauth/authorize with the client_id and redirect_uri as parameters.
- When this is successful, a parameter, "code", is sent back in the URL, to the external service
- Next, the external service must execute a POST call to https://[Your-App-URL]/version-test/api/1.1/oauth/access_token with parameters: "client_id", "client_secret", "redirect_uri", and "code". This is known as the token endpoint.
- Lastly, the app will respond with "access_token", "expires_in", and "uid" parameters that the external site can store for the user.
- The access_token is used in future calls to the Bubble app from the user within the external app (until expiry)
- Refreshing the token: In the POST body, set grant_type to “refresh_code” and send the refresh token as the refresh_token received previously. You will need to include the same client_id and client_secret used when getting the token in the first place.
Commonly asked questions relating to Oauth
When a user is already signed in, using the "Signup/Login with a social network" with an Oauth service will "link" that user's account on that service to their Bubble app user record.
Generally, no, if you're just using a plugin to provide Oauth login and if the plugin you're using was designed with this capability (and most generally are).
One case where you may need to handle refresh tokens is if you're building your own plugin or API connection to enable Oauth. For example, your app may have users authenticate into Google so that you can do things on their behalf with their Google data (e.g. check their email every X hours regardless of whether the user is active on your app). In these cases the plugins that provide Google Oauth will not be enough for your use case; you might want to build your own (or find a different plugin). If you're building your own plugin or API connection, here's some documentation suggesting how you'd handle the refresh token for Google in particular.
Oauth logins sometimes do have a natural timeout to help improve end-user security, but this is usually on the order of magnitude of days or longer. If you're seeing that your users can't stay logged in for shorter periods of time, there may be something amiss with the refresh tokens (the way that Oauth permission grants get automatically renewed over time).
These are tricky problems to debug because they often involve something going wrong with the plugin (or API connection) you're using or with your configuration with the third party itself. One thing to try is to install a different plugin offering Oauth with the same service, signing a test user up via that new plugin, and seeing if the same problem occurs for that user. If that doesn't help, the Forum may reveal other users who have solved the issue for that specific Oauth provider.
Different plugins for the same Oauth service are effectively treated like different Oauth services by Bubble. For example, if Plugin 1 and Plugin 2 both let you signup / login with Google, switching from 1 to 2 will NOT automatically preserve all your users' ability to log in with Google.
To handle this migration: let's assume you want to move from Plugin 1 to 2. Keep both plugins installed in your app for a little while. When users are logged in (e.g. via Plugin 1), prompt them to kick off a workflow that has the "Signup/Login with a social network" action with plugin 2 - this will associate 2's Oauth service with the user. After all or most of your users have done this, it's then safe to remove plugin 1. (Any stragglers could always add a password to their account via the reset password flow.)