October 15, 2023
Kazi Ehsan Aziz
So, you are coming from a traditional backend-handles-authentication scenario, i.e. you have written your own API endpoints that handle user registration and issuance of access tokens. But now you need to integrate Auth0 within your custom APIs. Auth0 is easier to use if you just let your client applications talk to their hosted APIs (in production, preferably behind your own Custom Domain) directly. Auth0 was designed to take care of authentication and authorization for you. But you can still build a traditional authentication backend with your own login and signup APIs, using Auth0's SDK.
First, the best thing to do is to go through Auth0 documentations and
familiarize yourself with their terminology (API, Application,
various flows, etc.). But it can still be a bit confusing. This
article will not explain in details how to setup Auth0. Rather,
it is a very concise guide for someone who has already tried to
integrate Auth0 within their existing API endpoints, but is still
in doubt about their setup. It will be impossible to follow this
guide if you have not already tried to setup Auth0 yourself.
Head over to Auth0's dashboard. Start with creating an API in the
existing Tenant.
A Database Connection is also created automatically.
Alongwith the API, a Machine to Machine Application is automatically
created which contains our domain, client_id and client_secret.
In "Auth0 Dashboard" -> "Applications" -> "Applications" ->
"YOUR_M2M_APP" -> "APIs", you will find this M2M Application
has been authorised to request access tokens for the API that
we just created. But this application has not yet been authorized
to request access tokens for the Auth0 Management API.
Under these settings, you can set up the Auth0 SDK in the following manner (shown in Python with FastAPI). This will allow you to sign up users.
from auth0.authentication import Database, GetToken
from src.core.config import settings
def auth0_authapi_database():
database = Database(settings.AUTH0_DOMAIN, settings.AUTH0_CLIENT_ID)
return database
def auth0_authapi_token():
token = GetToken(
settings.AUTH0_DOMAIN,
settings.AUTH0_CLIENT_ID,
client_secret=settings.AUTH0_CLIENT_SECRET,
)
return token
from fastapi import APIRouter, Depends
from fastapi.responses import Response
from auth0.authentication import Database, GetToken
from src.core.config import settings
from src.deps.auth0 import auth0_authapi_database, auth0_authapi_token
router = APIRouter()
@router.post("/v1/auth/signup", tags=["auth"])
async def signup(
auth0api_database: Database = Depends(auth0_authapi_database),
) -> Response:
response = auth0api_database.signup(
email="ehsan_1@yopmail.com",
password="Abc!_1234",
connection="Username-Password-Authentication",
)
return response
Resource Owner Password Flow
But in order to use sign-in with username and password, the M2M
Application needs to be given the password Grant Type in
"Auth0 Dashboard" -> "Applications" -> "Applications" ->
"YOUR_M2M_APP" -> "Settings" -> "Advanced Settings" ->
"Grant Types". This password Grant Type is what comprises a
Resource Owner Password Flow. Now you can sign-in.
# ...
@router.post("/v1/auth/signin", tags=["auth"])
async def signin(
auth0api_token: GetToken = Depends(auth0_authapi_token),
) -> Response:
response = auth0api_token.login(
username="ehsan_1@yopmail.com",
password="Abc!_1234",
realm="Username-Password-Authentication",
audience=settings.AUTH0_API_AUDIENCE,
)
return response
# ...
Client Credentials Flow
By default, an M2M only has the Client Credentials grant type.
In the Client Credentials Flow, you just provide the Application
client id and secret to obtain access tokens from Auth0. As such,
the access token has no user information, it is an access token
just for the Application itself authorised to use some API
declared in Auth0. Hence, the term Machine to Machine.
Authorization Code Flow
Now, it will be ok to go forward with the M2M Application created
for us and use its client_id to initialise the SDK. But if you
have plans in the future for your API Server to be consumed by a
frontend client where Authorization Code Flow might be adopted
(client provides backend with an OAuth code, which the backend
then exchanges with Auth0 for an access token), then you also need
the Authorization Code Grant Type.
But instead of adding yet another Grant Type Authorization Code
to our M2M application (which is only meant to have the Client Credentials
grant type), we can create a new Application of type
Regular Web App, which by default will have the
Authorization Code and Client Credentials grant types amongst
others. We need to add the password grant type manually here
as well.
So technically, any one of "Resource Owner Password" or "Client Credentials" or "Authorization Code" flows can be used with both M2M and Regular Web App type Applications.
You will also need the Auth0 Management API for user CRUD operations. In "Auth0 Dashboard" -> "Applications" -> "APIs" -> "Auth0 Management API" -> "Machine To Machine Applications", first authorize your M2M application to request access tokens for the Management API. Then expand the M2M Application to also add the required permissions (scopes).