External database vs. Auth0 data store
The Auth0 data store is customized for authentication data. Storing anything beyond the default user information should be done only in limited cases. Here’s why:- Scalability: The Auth0 data store is limited in scalability, and your Application’s data may exceed the appropriate limits. By using an external database, you keep your Auth0 data store simple, while the more efficient external database contains the extra data;
- Performance: Your authentication data is likely accessed at lower frequencies than your other data. The Auth0 data store isn’t optimized for high-frequency use, so you should store data that needs to be retrieved more often elsewhere;
- Flexibility: Because the Auth0 data store was built to accommodate only user profiles and their associated metadata, you are limited in terms of the actions you can perform on the database. By using separate databases for your other data, you can manage your data as appropriate and perform direct calls without use of Auth0’s .
- For example, you could have a Users table that lists each user authenticated by Auth0. Every time a user logs in, you could search the table for that user. If the user does not exist, you would create a new record. If they do exist, you would update all fields, essentially keeping a local copy of all user data.
- Alternatively, you could store the user identifier in each table/collection that has user-associated data. This is a simpler implementation suited to smaller applications.
User data storage example scenario
Auth0 provides a sample app, a mobile music application, that reflects the end-to-end user experience when using Auth0 with a custom external database. The sample app is an iOS app created using the Auth0 iOS seed project. The backend uses the Node.js API. For a visualization of the application’s overall structure, see the Mobile + API architecture scenario.Metadata
App metadata
The following data points from our mobile music application are appropriate to store inapp_metadata
:
- User’s subscription plan
- User’s right (or lack thereof) to edit featured playlists
app_metadata
instead of user_metadata
because they should not be directly changeable by the user.
User metadata
The following data points from our mobile music application are appropriate to store inuser_metadata
:
- Application preferences
- Details chosen by the user to alter their experience of the app upon login.
app_metadata
, the user can easily and readily change those stored in user_metadata
.
We can let the user change their displayName
, which is the name the user sees upon logging in and is displayed to other users of the app.
To display the user’s chosen identifier whenever they log in, we use a rule to get the user.user_metadata
value.
displayName
:

user_metadata
field:
{yourAccessToken}
with a Management API Access Token.
User data permission rules
Use rules to implement permissions on whether a user can edit featured playlists or not.Assign Playlist Editor role
The first rule sends a request to our Node API, which then queries the database connected to Heroku to check how many plays the user’s playlist has. If the number is 100 or greater, we assignplaylist_editor
as a value in the roles
array in app_metadata
.
Scope parameter specifies role
The second rule gets theapp_metadata
field and assigns the roles
array to a field in the user object so it can be accessed without calling app_metadata
on the application. The scope
parameter can then specify roles
upon the user logging in without including everything in app_metadata
in the user object:
playlist_editor
is in the roles
array stored in the user’s app_metadata
, the user will be welcomed as an EDITOR after signing in:

Associate a user’s music with the user
We need to associate a user’s music with that user, but this information is not required for authentication. Here’s how to store this information in a separate database that is integrated with the backend of the application. The user’s unique identifier is theuser_id
and it’s the sub-property of the idTokenPayload
object in an authResult
. Here is a sample row from the songs
table in our database:
song_id | songname | user_id |
---|---|---|
1 | Number One Hit | google-oauth2 |
GET
request to /secured/getFavGenre
, the API calls the queryGenre()
function, which queries the database for and responds with the user’s favorite genre.
buildAPIRequest()
takes the path and HTTP method of the request as parameters and builds a request using the base URL of our Node.js API that’s hosted on Heroku.
In the Application, the getGenre()
function makes a request to the API and changes the app’s interface to display the request response to /genres/getFav
. The backend retrieves the required data for this action using the queryGenre()
function and returns the results to the Application: