There’s of course no “right” answer when it comes to system design, but I think I would flip the responsibilities around here. Particularly, updating the application’s data store from a rule has a certain code smell.
Auth0, as the identity provider and OAuth2 authorization server will authenticate the user and issue access tokens to the application, that represent the permission that the user gives to the application to access the user’s resources (the To-Do list, in this case). But the chores of keeping the backend’s database in shape would be better done at the backend (the API), maybe driven by the application using the API.
A new user lands in the app after authenticating with the identity provider. You get the user id (the sub
) from Auth0. But the access token won’t have a “local user id”, because it’s a new user.
Now, does the to-do list need any kind of initialization (e.g. do you need any specific data or does the provisioning take some time)? Then you might provide an API for that:
POST /api/initialize
This would be the only endpoint available at this point. All the other endpoints for the API would do this check: does a local user exist for the sub
in the access token? If not, deny access.
The handler for /initialize
might create the local user, associate it with the Auth0’s user id, and maybe update the user profile on the Auth0 side, so that the next time you can include it in the access token. Your client app could re-authenticate the user at this point if the other API endpoints rely on the local user id being available on the token.
But note that having the local user id is just an optimization, you don’t really need it because you can simply use the relationship that you have in the data store, and fetch the local user id based on the sub provided in the token (and you can optimize your system to be good at this).
If you don’t want/need an initialization API, then you can probably do the initialization on the first access. E.g. on the handler for GET /api/todo
you can have a logic like this:
- Do I have a local user with a matching Auth0’s user id?
- Yes? then get the local user id and return the list.
- No? then create a new local user and return an empty list.
Hope that makes some sense.