How to prevent Auth0 from storing a database / history of Users?

We’re developing a medical app where it is important that we don’t collect a database of any user data such as emails.
We’ve set up Auth0 to use passwordless Email authentication, and a couple of social media logins like google and microsoft. This is great and our app receives the user’s name and email from a successful Auth0 login.

However we take issue with the fact that Auth0 themselves under Users & Roles > Users maintain a database that stores the information of everybody that has logged in and at what time.

Can we prevent this from happening? All Auth0 needs to store on their servers at most is the temporary session token. Especially since we don’t use a database on Auth0 at all, and we use passwordless & user-registration-less login methods.

We must be able to comply to GDPR rules of not collecting or having access to a database of stored personal info.

Hi @apd,

Welcome to the Community!

You can prevent user profile attributes from being stored by following the documentation here: https://auth0.com/docs/security/denylist-user-attributes

If this looks like what you are looking for, here are some steps to implement the user attribute deny list:

First, you’ll need an Management API Access Token that has the update:connections and read:connections scopes.

You can follow the guide for manually obtaining an access token: Get Management API Access Tokens for Testing

Next, you can get data for all of your connections using the /api/v2/connections endpoint. You’ll need the IDs and options object for each connection.

Finally, update each connection’s options object. Note: when you update the options object it will override what you currently have set, so be sure to add to the options objects that you collected from the GET endpoint.

The body of the request will look like this:

{
   "options":{
     // Any exiting options properties for the connection
    "non_persistent_attrs": ["email", "name", "email_verified", "family_name", "gender", "given_name", 
    "picture", "nickname", "locale"]
   }
}

As the guide mentions, the user’s information is still in the rule, so if you’d like to send some non-persistent user data in the ID Token, it should be available. However, if you are not getting the user data you need, you can add Custom Claims to the ID Token to a Rule:

function (user, context, callback) {
  const namespace = 'https://YOUR_APP_URL';
  let idTokenClaims = context.idToken || {};
  idTokenClaims[`${namespace}/email`] = user.email;
  context.idToken = idTokenClaims;

  callback(null, user, context);
}

Here is additional documentation related to Auth0 and GDPR compliance: Auth0 General Data Protection Regulation Compliance

Thanks! I saw no hints in the Users & Roles section, nor in the auth0 dashboard in general; so I thought it just wasn’t a feature. Especially since I had no databases in auth0 that I set up myself. So I thought we’re kinda stuck that way with that builtin database.

I’ll have a look more closely next week and accept the answer or do a follow up.

Hi, I read the stuff, but I don’t think we are talking about the same thing here. What I’m referring to, is this specific page on the Auth0 dashboard (see attached picture). This is essentially a log that Auth0 maintains outside of my control of all the people that have ever logged into my app and at what time, their Gravatar, their IP. This is not OK.

We need to tell our customers that neither we nor our third parties collect any identifiable data about who uses our medical products. Yet Auth0 collects this data.

Like I mentioned before, none of the login methods I’ve set up on Auth0 require Auth0 to collect this kind of database. I use passwordless (email codes) or accountless (social) registration methods, and our app needs to temporarily know the email of the user and that’s it.

All Auth0 needs to collect in this case for Auth0 to work, is an irreversibly hashed email or user id, so that I may ban it if necessary or whatever. Auth0 does not, for any purpose, need to cache or collect the actual email, the gravatar, or any other identifiable information. Nothing I enabled on Auth0, needs that info collected for later.

So. Is there any way I can disable this builtin Auth0 log of users in its current form? If not, we need to rebuild our login from scratch or use another third party instead of Auth0, one that doesn’t log for no reason…

When you add all of the profile data to each connection’s deny list as described above, the user will look like this in the dashboard (passwordless and Gmail):

If you would also like to obscure the IP address, you could probably use a Custom Domain and reverse proxy between Auth0 and users to strip out all the IP info from end-users. However, this would mean that you would not be able to leverage any of the Threat Detection features.

Do you have specific data residency or more detailed privacy restrictions regarding the no identifiable data requirement? Auth0 stores all of the data encrypted at rest and, in most cases, in transit. Our security and privacy posture allows us to store things that wouldn’t be possible in other solutions.

To get a more detailed solution specific to your implementation, you may want to consider reaching out to the sales team: https://auth0.com/contact-us

Hmm, okay. The deny list, to me, sounded like if I do that then I won’t be able to display the user’s own email in the app while the user is logged in. That database I screenshotted, is not really described in the auth0 website what it is, and I would either way have expected that settings for what is shown in that database, are available in the actual dashboard.

Alright, I will give that API a try. If I can still read the data that I deny, and jut prevent auth0 from logging it, then that should help.

1 Like

Sounds good. Yes, you’ll have to add a rule to be able to read the info in your app.

I don’t understand why this workflow/workaround is so different from the default ux of auth0… Suddenly I have to do these new api calls, that remove my own access from the user names/emails, just so I can prevent this weird auth0 table from logging them, and then have to add another rule to re-gain access… You’d think since GDPR happened, that you’d just have a button next to this table that says “don’t log these columns”…

The way I understand this is, I have to make this curl request to get a token:

curl --request POST --url ‘https://MY_APP.eu.auth0.com/oauth/token’ --header ‘content-type: application/x-www-form-urlencoded’ --data ‘client_id=MY_APP_CLIENT_ID_GOES_HERE’ --data ‘client_secret=MY_APP_CLIENT_SECRET_GOES_HERE’ --data ‘audience=https://MY_APP.eu.auth0.com/api/v2/’ --data grant_type=client_credentials

^ doesn’t work.
Says {"error":"unauthorized_client","error_description":"Grant type 'client_credentials' not allowed for the client.","error_uri":"https://auth0.com/docs/clients/client-grant-types"}
The docs seem to say that I’m not allowed by default to get a token this way. Is this an administration token? If I enable the ability to obtain this token via this type of curl request, will it then open up security holes?

Then once I get some kind of token, I should do:

curl --request PATCH --url ‘https://MY_APP.eu.auth0.com/api/v2/connections/[…]’ --header ‘authorization: Bearer MY_TOKEN’ --header ‘content-type: application/json’ --data ‘{“options”: {“non_persistent_attrs”: [“ethnicity”, “gender”, “name”, “email”, “browser”, “nickname”, “picture”]}}’

And then like you said, change my app code somewhere to add a rule to be able to read the info at the time of the user log in.

This whole thing has been unrolling into multiple unclear things :slight_smile: not exactly what I would call frictionless authentication

It’d be great to get your feedback for our product team’s review: Feedback - Auth0 Community

If you’re building an app that needs to interact with the Managment API regularly, then you’d need to set up a Machine to Machine Application so that the app would be allowed to use the client credentials grant type. Since you only need to make this update once to test out this setting, you could use the API explorer:

Go to the Auth0 Management API and click on the API Explorer tab and copy the token:

Paste the token in the Management API’s docs page:
screenshot-auth0.com-2021.03.15-08_59_01

And then you can find the connection IDs with the Auth0 Management API v2 endpoint and paste the payload into the Auth0 Management API v2 endpoint using the IDs:

{
   "options":{
     // Any exiting options properties for the connection
    "non_persistent_attrs": ["email", "name", "email_verified", "family_name", "gender", "given_name", 
    "picture", "nickname", "locale"]
   }
}

Rules are javascript functions that run after authentication. These are set up in the dashboard, so no code change is needed in the application itself:

screenshot-manage.auth0.com-2021.03.15-09_03_14

The rule is needed because any user info on the deny list would not otherwise be returned. The rule will add the email in the ID token in a custom claim even though that attribute is on the deny list.

Here’s additional info on Auth0 and GDPR: Auth0 General Data Protection Regulation Compliance

1 Like

Ok well, when you say it like that, it makes a lot more sense :stuck_out_tongue: You’ve filled in a lot of blanks. (I was looking at the app, not the Auth0 Management API; I knew that you could add javascript functions that run after authentication, but didn’t think that’s the right stage for this and forgot that they are called “Rules”; and the explanation of why the rules are needed also makes sense)

One thing though. I made this rule, and it works when I try it in the dashboard, but when I run the app, it returns empty name, email etc. I suspect the “namespace”. I don’t really understand from the docs what that is. You say it should be my app url. Not sure what that means. It’s a mobile app not a website; it doesn’t have a url, and there is no url per se in the app’s settings in the dashboard…

function (user, context, callback) {
const namespace = ‘https://myAuth0AppName.com/claims’;
let idTokenClaims = context.idToken || {};
idTokenClaims[${namespace}/nickname] = user.nickname;
idTokenClaims[${namespace}/name] = user.name;
idTokenClaims[${namespace}/email] = user.email;
idTokenClaims[${namespace}/picture] = user.picture;
context.idToken = idTokenClaims;

return callback(null, user, context);
}

But you’ve been super helpful, thanks. And don’t take any of my frustration as something directed at you, it was all about the general ux of things.

And yes, it would be nice if I took time to detail the ux and information issues with the system and write it in the feedback forum. But who’s gonna take time to do this reiterating for free for auth0? :slight_smile: Maybe you can casually point some feedback team members to read this conversation and break down themselves, the UX issues and lack of information that happened at each step during this case; make their own feedback post.

I’m happy I could help clear some things up! That is understandable. It can get quite complicated since there are so many ways to customize and extend the implementation. This is also not a standard implementation, and so it requires some workarounds. Again, it’d be great to get your use case in a feature request in the feedback category!

In order to avoid ID Token claim collision, any custom claims must be namespaced using a URI. This does not need to be a real URL, although using a URI of a resource you control is the best way to ensure it is unique. You can find more info on namespacing custom claims here: Create Custom Claims

Including these user attributes as custom claims is a workaround since the user’s info will not be included in the ID Token since the info is on the deny list. This way the user info is accessible in the initial ID Token, but nowhere else in the system.

You can decode the ID Token you receive after log in at https://jwt.io/. You should see the namespaced claims in the ID Token. Your app can refer to these claims to access the user info. For example (using React in this example):

export const ProfileComponent = () => {
  const { user } = useAuth0();

  return (
    <Container className="mb-5">
      <Row className="align-items-center profile-header mb-5 text-center text-md-left">
        <Col md>
          <p>Email: {user['https://YOUR_NAMESPACE/email']}</p>
        </Col>
      </Row>
    </Container>
  );
};

Also, if silent authentication takes place, these custom claims about the user won’t be available since Auth0 will not persist any attributes on the deny list. This info would only be available in the initial ID Token after log in.

1 Like

Dang I think that might be what is happening. I was assuming / hoping, that the name/email etc are being received, directly from the source (e.g. google) even on silent authentication.

Ok I will look into it this week and either accept the answer or follow up. And maybe make a feedback post because this should really be a more standard feature.

1 Like

Ok I have solved everything as intended for the GDPR no-logging strategy.

Some final points:

  • When I created these namespaced custom claims, I had to also change the requested claim type in my app code from the default/initial “email” to the new namespaced format “www.mydomain.com/uri/email” (so actually that’s why I was seeing a successful test of the Rules in the Auth0 dashboard, but in my app I was getting empty “email” claims :slight_smile:)
  • after you set all this up (get connections ids, patch connections, set Rules) you have to delete all the existing users from the Users & Roles table, because the names & emails etc are not retroactively removed from the logs even when the same user logs-in again after the changes.
  • Auth0 is actually very customizable, but there is no top-down, or, big picture way of noticing that it is. So without Stephanie’s help, I would have either thought it’s impossible, or would have literally had to read half of the documentation not knowing what I want until it somehow clicks what you can do. There should really be some hints based on “if you want to achieve this then do x” or “did you know you can configure this by going in the management api and then in the rules functions?”.

I’ve created a post in the feedback forum about this and more specifically the request for a log-less users log :slight_smile:

2 Likes

Great, I’m so glad to hear you reached a solution!

Thanks again for the feedback, and that is good for us to know. We are working towards answering some of these “if you want to achieve this then do x” in the FAQ section. I believe a topic on the deny list feature would be a good addition!

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.