Best practices for authenticating API requests from domains you don't control

I’m trying to figure out best practices for authenticating API requests from domains that I don’t control, and I’d appreciate some guidance.

My setup: We have a web app that uses Auth0 for IAM. The web app exposes an API (app.foo.com/api) that authenticates requests using a JSON Web Token, and we allow users to generate tokens for their account through the authorization code flow provided by Auth0. This workflow is configured as an Application in Auth0, although it corresponds to an API.

On top of this, there exists a skinned frontend for the web app that a client of ours maintains separate from us. The skinned frontend interacts with our API with requests originating from a separate domain (app.bar.com), and it has its own Auth0 tenant so that users of the skinned site can authenticate to it while the skinned frontend accesses our API via a custom social connection (set up via an Auth0 extension).

The current situation: Our client is now developing a third site (ann.bar.com) that they want to use to consume our API. We don’t necessarily want to replicate our current approach with this new site because it doesn’t seem ideal. For one, we are continually appending Allowed Callback URLs for domains that we have no control over. I’m wondering what the best practice is for administering API tokens to users of this third site via the identity that they have established in the Auth0 tenant for the skinned frontend?

Based on the Auth0 docs for multi-party authentication, it seems like the recommended workflow is to instruct our client to set up a redirect rule during their authentication that would ask our API for a token. On our side, we would need to configure the Allowed Callback URLs for our API Application to whitelist their domain, and potentially make other changes to permit our Auth0 tenant to provision tokens to their app.

Another possible workflow seems to be to authenticate using OpenIDConnect to another Auth0 tenant. I believe we tried and failed to implement this solution about a year ago, when there was a known bug preventing OIDC connections between Auth0 tenants.

Which of these workflows is the right fit for our situation? If one workflow stands out as the right one to pursue, are there any additional docs or tutorials that might help us understand how to implement it?

A couple of questions before rushing an answer:

  • When your API is accessed by your clients application, should it be accessed on behalf of the user using the application? Or is your API a generic service that the application would access on its own (think, for instance, of a database, an email delivery service, an SMS service, and so on).
  • Do you need to let your customers decide how to authenticate their users? Or should all the users reside in your own Auth0 domain?

Thanks for the clarifying questions, Nicolas!

When your API is accessed by your clients application, should it be accessed on behalf of the user using the application?

Yes, the API should be accessed on behalf of the user. A primary function of the API is storing and retrieving data that users upload and curate on their accounts.

Do you need to let your customers decide how to authenticate their users? Or should all the users reside in your own Auth0 domain?

This is a good question, and I’m not completely sure of the answer. I believe that we’d like to give our clients as much freedom as possible to make decisions about authentication (without compromising security on our end, of course). Right now we have clients set up on their own Auth0 tenants. But if the answer to this question changes the recommendation you’d make, I’d be curious to hear how.

Thanks for the responses, I’ve got a clearer view now.
By your description, you should have:

  1. One single Auth0 tenant (e.g. foo.auth0.com), ideally with a custom domain (e.g. id.foo.com). In this Auth0 tenant you would define the API for which Auth0 will issue access tokens (Authentication and Authorization Flows).

  2. Your first-party application(s) defined in the same Auth0 tenant, with any connections that make sense.

  3. For each customer that wants to use an application to consume your API you would create a Third-party app. You can do this manually for a few customers and move to a self-service dashboard-type admin site (using management API v2 to create the clients) when your customer base grows. Each customer app would have their own callback URLs and application type settings.

  4. You can have a handful of “standard” connections for third-party apps if it makes sense (e.g. Username-Password-Authentication and a few social connections). As explained in the docs, these connections need to be promoted to “domain connections” so that they can be used by third-party apps. These would be the “shared” user stores, for those customers that don’t need to use a custom authentication method.

  5. Your customers will always request tokens to your Auth0 domain using the assigned client id and specifying your API as the audience (which you can make the default for your tenant to avoid using the audience parameter).

  6. For customers that want to federate authentication (i.e. want to use their own authentication method) you can create enterprise connections (any of the enterprise connection types offered in your Auth0 tenant). So, for example, Acme wants to use Azure AD to authenticate their users. You’ll create an Azure AD connection associated to the acme.com domain. This way (and if using Lock) when a user types an @acme.com email address, Lock will detect that and send a login request to the appropriate Azure AD domain.
    By using enterprise connections, you can let your customers use any of the common authentication federation method without forcing them to use Auth0 (even though Auth0 would be a great choice for an identity provider :slight_smile: ). If your customer wants to use Auth0, you can create a SAML connection to the third-party Auth0 domain.

OK, I probably wrote too much, happy to clarify any point.

Thank you for this detailed reply, Nicolas! I think this gives us the direction we need to get started. I’ll take a look at the API workflow with first- and third-party tenants and follow up if I have further questions.