Migrating from Keycloak to Auth0 - Guidance Needed on for separate frontend SPA's and Laravel Statless API

Hello, Community!

I am currently in the process of migrating from Keycloak to Auth0 for managing authentication in my closed-source projects. . I’m aiming to solve an issue related to this migration and your insights would be greatly appreciated. Once resolved, updates to the code and instructions will be shared in my open-source project repositories.

Project Description:

  • I’m building a stateless Laravel API without sessions, consisting of two endpoints: /api/public (for Customers’ SPA) and api/admin (for Operations’ SPA).
  • I intend to rely on the Auth0 SDK for authentication, foregoing Laravel Passport and other Laravel auth implementations.
  • The frontend SPAs and Laravel API are designed as separate, independent projects.
  • The frontend users (Customers and Operations) authenticate directly on Auth0 to obtain JWT access tokens.
  • The frontend apps retain these access tokens and make requests to the Laravel API.

Customers Flow:

  1. Customers authenticate on Auth0 via email or social providers. The Auth0 database customers-authentication is used here.
  2. Upon authentication, the customer obtains a JWT token.
  3. This token is used for accessing protected Laravel API endpoints.
  4. Auth0 Guard within Laravel API processes the token, verifying its signature, structure, expiry time, and resource access permission.
  5. If the token is verified, the Laravel API searches for the user in the database via the auth0_id. If the user doesn’t exist, a new entry is created using the access token data.
  6. A response is then returned to the frontend application.

Operations Flow:

  • Similar to the Customer flow, except Operations users authenticate on Auth0 without registration. Only existing Auth0 dashboard users can be added. The Auth0 database operations-authentication is used, which is separate from customers-authentication. Sign Up is disabled for this database.


  • Operations users can only log in to the Operations application.
  • Customers users can only log in to the Customers application.


  1. How can I tie the Customers Application with the Customers API effectively?
  2. What’s the best way to link the Operations Application with the Operations API?
  3. Is it feasible to use the accessToken returned by the frontend (Separate Project) for making requests to my Laravel API?
  4. As the accessToken doesn’t include data such as email, how can I register users? Two potential options I see are:
    • Adding the email to the accessToken before sending it to the backend API application
    • Utilizing the Management API to retrieve client details on receiving a request from the frontend, and then creating the user in my Laravel API database
  5. What’s the recommended way to integrate the Management API and which applications should have access to it?
  6. How to correctly get API management token on Laravel API side? Can I use api-explorer token for this?

Here is my current keycloak flow:

Here is how I configured Auth0:

Applications and Databases:


I have checked tons of Auth0 examples in various articles and also github, none of them shows full cycle implementation for stateless API


Here is example auth0.php config file:

return Configuration::VERSION_2 + [
    'registerGuards' => false,
    'registerMiddleware' => false,
    'registerAuthenticationRoutes' => false,
    'configurationPath' => null,

    'guards' => [
        'default' => [
            Configuration::CONFIG_STRATEGY => Configuration::get(Configuration::CONFIG_STRATEGY, SdkConfiguration::STRATEGY_NONE),
            // Configuration::CONFIG_DOMAIN => Configuration::get(Configuration::CONFIG_DOMAIN),
            Configuration::CONFIG_CUSTOM_DOMAIN => Configuration::get(Configuration::CONFIG_CUSTOM_DOMAIN),
            Configuration::CONFIG_CLIENT_ID => Configuration::get(Configuration::CONFIG_CLIENT_ID),
            Configuration::CONFIG_CLIENT_SECRET => Configuration::get(Configuration::CONFIG_CLIENT_SECRET),
            Configuration::CONFIG_AUDIENCE => Configuration::get(Configuration::CONFIG_AUDIENCE),
            Configuration::CONFIG_ORGANIZATION => Configuration::get(Configuration::CONFIG_ORGANIZATION),
            Configuration::CONFIG_USE_PKCE => Configuration::get(Configuration::CONFIG_USE_PKCE),
            Configuration::CONFIG_SCOPE => Configuration::get(Configuration::CONFIG_SCOPE),
            Configuration::CONFIG_RESPONSE_MODE => Configuration::get(Configuration::CONFIG_RESPONSE_MODE),
            Configuration::CONFIG_RESPONSE_TYPE => Configuration::get(Configuration::CONFIG_RESPONSE_TYPE),
            Configuration::CONFIG_TOKEN_ALGORITHM => Configuration::get(Configuration::CONFIG_TOKEN_ALGORITHM),
            Configuration::CONFIG_TOKEN_JWKS_URI => Configuration::get(Configuration::CONFIG_TOKEN_JWKS_URI),
            Configuration::CONFIG_TOKEN_MAX_AGE => Configuration::get(Configuration::CONFIG_TOKEN_MAX_AGE),
            Configuration::CONFIG_TOKEN_LEEWAY => Configuration::get(Configuration::CONFIG_TOKEN_LEEWAY),
            Configuration::CONFIG_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_TOKEN_CACHE),
            Configuration::CONFIG_TOKEN_CACHE_TTL => Configuration::get(Configuration::CONFIG_TOKEN_CACHE_TTL),
            Configuration::CONFIG_HTTP_MAX_RETRIES => Configuration::get(Configuration::CONFIG_HTTP_MAX_RETRIES),
            Configuration::CONFIG_HTTP_TELEMETRY => Configuration::get(Configuration::CONFIG_HTTP_TELEMETRY),

            Configuration::CONFIG_DOMAIN => env('AUTH0_ADMIN_DOMAIN'),
            Configuration::CONFIG_MANAGEMENT_TOKEN => env('AUTH0_MANAGEMENT_API_TOKEN'),
            // Configuration::CONFIG_MANAGEMENT_TOKEN => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN),

            Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE),
            Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY),
            Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST),

        'api-admin' => [
            Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_API,
            Configuration::CONFIG_DOMAIN => env('AUTH0_ADMIN_DOMAIN'),
            Configuration::CONFIG_CLIENT_ID => env('AUTH0_ADMIN_CLIENT_ID'),
            Configuration::CONFIG_CLIENT_SECRET => env('AUTH0_ADMIN_CLIENT_SECRET'),
            Configuration::CONFIG_AUDIENCE => [env('AUTH0_ADMIN_AUDIENCE')],
            Configuration::CONFIG_MANAGEMENT_TOKEN => env('AUTH0_MANAGEMENT_API_TOKEN'),

        'api-public' => [
            Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_API,
            Configuration::CONFIG_DOMAIN => env('AUTH0_PUBLIC_DOMAIN'),
            Configuration::CONFIG_CLIENT_ID => env('AUTH0_PUBLIC_CLIENT_ID'),
            Configuration::CONFIG_CLIENT_SECRET => env('AUTH0_PUBLIC_CLIENT_SECRET'),
            Configuration::CONFIG_AUDIENCE => [env('AUTH0_PUBLIC_AUDIENCE')],
            Configuration::CONFIG_MANAGEMENT_TOKEN => env('AUTH0_MANAGEMENT_API_TOKEN'),

Here is configured laravel auth.php:



return [
    'defaults' => [
        'guard' => 'api-public',

    'guards' => [
        'api-admin' => [
            'driver' => 'auth0.authorizer',
            'provider' => 'auth0-provider',
            'configuration' => 'api-admin',
        'api-public' => [
            'driver' => 'auth0.authorizer',
            'provider' => 'auth0-provider',
            'configuration' => 'api-public',

    'providers' => [
        'auth0-provider' => [
            'driver' => 'auth0.provider',
            'repository' => 'auth0.repository',
            // 'repository' => \Infrastructure\Persistence\Auth0\ClientRepository::class,

1 Like