Joomla 4 and Joomla 5 introduced a powerful Web Services API that allows developers to interact with their content programmatically. By default, this API is locked down tightly, requiring an API token or Basic Authentication for almost every request. While this is excellent for security, it can be a hurdle when you want to use the Joomla API to fetch public data—like a list of blog posts or public events—for a decoupled front-end or a mobile application.

In this guide, you will learn how to bypass the mandatory authentication for specific GET requests, allowing you to serve public data through the Joomla API without exposing sensitive credentials in your client-side code.

Understanding Joomla API Authentication

By default, the Joomla API uses a secure-first approach. Even if an article is set to 'Public' on your website, the API endpoint for that article typically requires an Authorization header. This is because the API is designed to handle not just reading data, but also creating, updating, and deleting it.

When you attempt a request without a header, you likely see a 401 Unauthorized error. While you can use Basic Authentication for testing, as shown in the example below, you should never hardcode these credentials in a public JavaScript file:

# Example of a secure request using Basic Auth
curl -X GET http://your-site.com/index.php/v1/content/articles --header 'Accept: application/vnd.api+json' --header 'Authorization: Basic YWRtaW46YWRtaW4='

To make this data accessible to everyone without the header, we need to tell Joomla's router that specific routes are 'public'.

Method 1: Making Existing Routes Public via a Plugin

If you want to make core Joomla routes (like Articles or Categories) or routes from a third-party extension public, the most effective way is to create a custom system plugin. This plugin hooks into the routing process and flips the public flag to true for specific methods.

The onBeforeApiRoute Event

Joomla provides the onBeforeApiRoute event specifically for modifying API routes before they are finalized. To use this, you must create a plugin in the webservices group.

Important Note: Your plugin must be ordered to run after the plugins that register the routes you want to modify. In the Joomla Administrator, go to System > Plugins and ensure your custom plugin has a higher execution order than the core Web Services plugins.

Here is the implementation logic for your plugin's main file:

public function onBeforeApiRoute($router)
{
    // Iterate over the registered routes in the API router
    foreach ($router->getRoutes() as $route)
    {
        // We only want to make GET requests public to prevent unauthorized data modification
        if ($route->getMethods() === ['GET'])
        {
            // Retrieve the current route defaults
            $defaults = $route->getDefaults();

            // Set the public flag to true
            $defaults['public'] = true;

            // Apply the modified defaults back to the route
            $route->setDefaults($defaults);
        }
    }
}

Why This Works

Joomla's ApiRouter stores metadata for each route in a 'defaults' array. By setting public => true, you are telling the authentication layer of the API to skip the credential check for that specific endpoint. By wrapping this in a check for the GET method, you ensure that POST, PATCH, and DELETE requests still require full authentication, maintaining the integrity of your site's data.

Method 2: Defining Public Routes in Your Own Extension

If you are a developer building your own Joomla component and want to offer a public API out of the box, you don't need a separate plugin. You can define public access directly when you register your routes.

Using createCRUDRoutes

When using the helper method createCRUDRoutes(), the fourth argument is a boolean that determines if GET requests should be public.

$router->createCRUDRoutes(
    'v1/mycomponent',
    'mycomponent',
    ['component' => 'com_mycomponent'],
    true // Setting this to true enables public GET access
);

Manual Route Registration

If you are defining a custom route manually, you can pass the public flag within the defaults array (the fifth argument of the Route constructor):

use Joomla\Router\Route;

$route = new Route(
    ['GET'], 
    'v1/my-custom-endpoint', 
    'mycontroller.display', 
    [], 
    ['public' => true]
);

$router->addRoute($route);

Best Practices and Security Risks

While enabling public access is convenient, it comes with significant responsibilities. Modern Joomla development requires a "security by design" mindset.

  1. Avoid Global Public Access: The plugin code provided in Method 1 makes every GET route public. This includes user profiles, configuration metadata, and potentially private logs. It is highly recommended to filter by component or URL pattern.
  2. Filter by Route Name: Instead of a blanket foreach, check the route name: php if (strpos($route->getName(), 'com_content') !== false) { // Only make article-related routes public }
  3. Data Minimization: Ensure your API controllers do not output sensitive fields (like email addresses or hashed passwords) even if the route is public. The Joomla API uses JSON:API specifications; use Fields to limit what is returned.
  4. Rate Limiting: Public APIs are targets for scraping. Consider using a Web Application Firewall (WAF) or a Joomla plugin to limit the number of requests from a single IP address.

Common Mistakes to Avoid

  • Incorrect Plugin Group: Ensure your plugin is in the plugins/webservices folder. If it's in plugins/system, the onBeforeApiRoute event may not trigger correctly in the API context.
  • Ignoring the Namespace: Joomla 4 and 5 rely heavily on PHP namespaces. Ensure your plugin file has the correct namespace declaration at the top, or Joomla will fail to load the class.
  • Caching Issues: Sometimes API responses are cached. If you change a route from private to public and still get a 401, clear your Joomla cache and any external caches (like Varnish or Cloudflare).

Frequently Asked Questions

Is it possible to make only specific articles public in the API?

No, the public flag applies to the route (the endpoint), not the individual data record. To control access to specific articles, you should use Joomla's built-in Access Control Levels (ACL). If an article is 'Registered', the API will still return a 403 Forbidden even if the route itself is 'public'.

Does this work in Joomla 5?

Yes. The API architecture in Joomla 5 is identical to Joomla 4 in this regard. The onBeforeApiRoute event and the Route class defaults remain the standard way to handle public access.

Can I enable public POST requests?

Technically, yes, by changing the method check to POST. However, this is extremely dangerous as it allows anyone to create content on your site. Only do this if you have implemented other robust security measures like ReCaptcha or strict validation.

Wrapping Up

Enabling public access to the Joomla API is a game-changer for building modern, fast, and integrated web experiences. By using the onBeforeApiRoute event or configuring your component's router correctly, you can serve data to your users without the overhead of authentication headers. Always remember to narrow the scope of your public routes to just the data you need to share, keeping your Joomla installation secure and performant.