Building first app - need architecture/design help

Hey Everyone,

For the past few months I have been building an iOS app using Vapor 3 as my backend. Initially I was using Vapor’s authentication/authorization library that comes standard. For the most part I felt pretty good until I was recommended Auth0. As far as the app goes, it’s a very basic CRUD app. A user logs in, and the backend would be called to retrieve only the list of items for that user.

The way I have Auth0 working now is not something I believe is correct.

First the user logs in. The response containing the access token and id token comes back. The access token is in the format of a string and gets stored in my keychain. When it comes time to add or get my list, I pass the access token to my backend. My backend calls the /userInfo endpoint in Auth0 to retrieve who the token belongs to and to validate it. Once it’s validated I can get the user who made the call.

Based on a few of the things i’ve come across I don’t believe this is correct as I keep reading that my access token should not be a string and should be some longer value. I am fairly new to the concept of auth tokens and what not and can really benefit from some guidance aimed towards beginners. Most of the docs i’ve found here seem more for a person who understands authentication :slight_smile:

My second issue that I believe I am doing something wrong is how I have implemented a friend’s list. So I want users to be able to add each other as friends, however my database is storing the userID because that is the only thing that can stay the same. Emails and names can change and I don’t know how I can keep my database sync’d. So what I do when a user goes to the friends list, I first have to get a list of all the user IDs that the user is friends with. I then call one of the management APIs and pass in each of the userIDs to get an email. I feel like this approach is wrong as well as I have to call the management API every so often. I eventually get the Too Many requests. Is that from calling the API to validate my access token or is it from the way i’ve implemented my friend list?

Regarding the first question:

You are correct that if the access token is meant for your own backend, it shouldn’t be an opaque string but a JWT, at least this is the format that Auth0 uses for such. The tokens are JWT and therefore self-contained.
In order to get the access token in JWT, and not this opaque string, is to first register your backend as API in Auth0, under Dashboard > APIs. You would provide an API identifier in the form of a URL (this doesn’t have to be publicly available, it’s just an identifier. Let’s say you name it https://example-api/

Then, when you make the authorization request within your iOS app, make sure you add the audience parameter to the request, like:

audience: https://example-api/

(you add it as parameter at the same place in your code where you also use the scope, clientID parameter, etc.)

You would then also define permissions/scopes for the API in the Auth0 Dashboard, which you can then request from your iOS app. This could be something like a scope add:friend, so when making the request to get the access token, you would extend the scope parameter like this for example:

scope: openid profile email add:friend

This way the access token you’d be getting back would then be valid to allow a user to add a friend via your backend API.

Note that both the ID Token and the Access Token contain a claim named sub (short for subject), which is actually already the unique user identifier (the user_idin a user profile in Auth0). Since you have it in both ID and access token, you could actually already use it. No need to additionally call the /userinfo endpoint necessarily here. And this is also the reference that you could use on your end to refer to users (as the foreign key in your DB tables so to speak).

This links might be helpful in general on how to protect your own backend/API:

https://auth0.com/docs/microsites/protect-api/protect-api

Regarding the second issue:

Storing the user_id as you do is fine, and makes sense. This is also what I would do, and using the user_id as the reference.

I feel like this approach is wrong as well as I have to call the management API every so often. I eventually get the Too Many requests. Is that from calling the API to validate my access token or is it from the way i’ve implemented my friend list?

You’re most likely hitting the rate limits here (it’s not about the access token validation).

I then call one of the management APIs and pass in each of the userIDs to get an email. I feel like this approach is wrong as well as I have to call the management API every so often.

Do you call the management API one by one for each user whose email address you want to fetch? Or are you calling the entire user list and caching the list for a while on your end? (Would this be an option to reduce the number of calls maybe?)

Thanks for the quick response! A couple of follow ups if you don’t mind.

So upon registering my backend as an API in auth0, you mentioned I would need to add the audience parameter to the request when authorizing.

Where exactly do I add that? When following some of the docs, my loading page brings up the auth0 login page where I do not see any of the parameters that you mentioned like audience, scope, etc.

Lock
                .classic()
                .withOptions {
                    $0.closable = false
                    $0.oidcConformant = true
                    $0.logHttpRequest = true
                }
                .withStyle {
                    $0.title = "Welcome to my App!"
                }
                .onAuth {

Ok, so you are using the embedded/native login rather than the browser-based one.
(Referring to Mobile Device Login Flow Best Practices)

I’m not too familiar with iOS dev and the iOS SDK myself, especially not with the native Lock (as we recommend the browser-based option usually), but it would be something like on here I assume (just give it a try):

Lock
                .classic()
                .withOptions {
                    $0.closable = false
                    $0.oidcConformant = true
                    $0.logHttpRequest = true
                    $0.scope = "openid profile email add:friend"
                    $0.audience = "https://example-api/"
                }

(Just got that looking at auth0-ios-swift-sample/HomeViewController.swift at embedded-login · auth0-samples/auth0-ios-swift-sample · GitHub)

If using the browser-based approach, like on Auth0 iOS / macOS SDK Quickstarts: Login, it would definitely be like this:

Auth0
    .webAuth()
    .scope("openid profile email add:friend")
    .audience("https://example-api/")
    .start {
        switch $0 {
        case .failure(let error):
            // Handle the error
            print("Error: \(error)")
        case .success(let credentials):
            // Do something with credentials e.g.: save them.
            // Auth0 will automatically dismiss the login page
            print("Credentials: \(credentials)")
        }
}

Thanks - i’ll take a deeper look through the repository you linked and play around with it some more. Thanks for your help!

1 Like

Let us know @dannyd2592 if you have any further questions!

So I finally corrected my token issue and receive a token in JWT form and made the changes to my backend. I now don’t run into the rate limit issue anytime I load my initial list since I was calling the Management API. Thanks for your help on that!

I do have a follow up question.

At the moment I do - I am planning on revisiting how I manage the whole friends list as I don’t think it’s optimized as well as it can be. But this does lead to my question. If the limit is 5 calls a minute - if I had 5 people simultaneously access their friend list. Even if I get the backend to only call the service once, wouldn’t that get me to the limit giving the 6th person an error?