Testing your authentication flows locally during development is a surprisingly tricky business, often involving more boilerplate than actual application code.
Let’s get a local Auth0 setup running so you can test your app without hitting the actual Auth0 service. We’ll use Docker for this.
First, you need a docker-compose.yml file. This will define our Auth0-like service.
version: '3.7'
services:
auth0-emulator:
image: auth0/auth0-emulator:latest
ports:
- "9080:80" # Map local port 9080 to the container's port 80
environment:
# These are the critical settings for your local Auth0
- AUTH0_DOMAIN=auth0-emulator:80 # Internal domain for the emulator
- AUTH0_CLIENT_ID=local-client-id # Your app's client ID
- AUTH0_CLIENT_SECRET=local-client-secret # Your app's client secret
- AUTH0_ISSUER=http://auth0-emulator:80 # The issuer URL
- AUTH0_AUDIENCE=http://localhost:3000 # Your app's API audience (if applicable)
volumes:
- ./auth0-emulator-data:/data # Persist emulator data
networks:
- app-network
networks:
app-network:
driver: bridge
You’ll also need a directory for the emulator’s data: mkdir auth0-emulator-data.
Now, let’s start the emulator:
docker-compose up -d auth0-emulator
This command pulls the auth0/auth0-emulator:latest image and starts it in detached mode. It maps local port 9080 to the container’s port 80. The environment variables are crucial:
AUTH0_DOMAIN: This is the domain your application will use to communicate with the emulator. We’re usingauth0-emulator:80because that’s how services on the same Docker network resolve each other.AUTH0_CLIENT_IDandAUTH0_CLIENT_SECRET: These are dummy values your application will use. You’ll configure these in your app’s environment variables.AUTH0_ISSUER: This is the URL Auth0 uses to identify itself.AUTH0_AUDIENCE: If your application acts as an API, this is the identifier for that API.
Your application’s configuration will need to point to http://localhost:9080 for the Auth0 domain.
Here’s a snippet of what your application’s authentication configuration might look like (using Node.js and auth0-react as an example):
// authConfig.js
import { Auth0Provider } from '@auth0/auth0-react';
const auth0Domain = process.env.REACT_APP_AUTH0_DOMAIN || 'localhost:9080'; // Point to your local emulator
const auth0ClientId = process.env.REACT_APP_AUTH0_CLIENT_ID || 'local-client-id'; // Match emulator's client ID
const auth0Audience = process.env.REACT_APP_AUTH0_AUDIENCE || 'http://localhost:3000'; // Match emulator's audience
const Auth0ProviderWithHistory = ({ children }) => {
return (
<Auth0Provider
domain={auth0Domain}
clientId={auth0ClientId}
audience={auth0Audience}
redirectUri={window.location.origin}
scope="read:current_user openid profile email" // Example scopes
>
{children}
</Auth0Provider>
);
};
export default Auth0ProviderWithHistory;
And in your index.js or App.js:
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import Auth0ProviderWithHistory from './authConfig';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Auth0ProviderWithHistory>
<App />
</Auth0ProviderWithHistory>
</React.StrictMode>
);
When you run your application, it will attempt to authenticate against http://localhost:9080. The auth0-emulator service will intercept these requests. You can then interact with your local Auth0 by visiting http://localhost:9080 in your browser. This is where you’ll create users, configure applications, and manage rules.
The auth0-emulator is essentially a simplified, self-contained version of Auth0. It simulates token issuance, user authentication, and basic user management. It’s not a full-fledged Auth0 replica; it’s designed to provide the core authentication and authorization functionalities needed for local development and testing. The emulator uses a local SQLite database to store user information and configurations, which is persisted via the auth0-emulator-data volume. This means your local user data and settings will survive container restarts.
A common point of confusion is the AUTH0_DOMAIN setting in the docker-compose.yml. When your application runs on your local machine and tries to reach localhost:9080, it’s using your host machine’s network. However, the auth0-emulator container, when it needs to refer to itself internally (e.g., when issuing tokens), uses its internal Docker network name, which is auth0-emulator. The auth0-emulator:80 syntax tells the emulator to use its own service name within the Docker network. When your app makes the external request to localhost:9080, Docker’s port mapping handles the translation.
When you’re done, stop the emulator with docker-compose down.
The next step is to explore how to simulate different user scenarios, like expired tokens or invalid credentials, using the emulator’s administrative interface.