DxpLife The practical Liferay DXP knowledge hub
Talk to us

Home/Knowledge Hub/Client extensions & integration

Client extensions & integration

Microservice Client Extensions in Liferay DXP

Architecture, configuration, OAuth 2, deployment, security and integration

In-depth guideAdvanced48 sections~15 min read
In this resource. How to run services outside the Liferay JVM and still integrate them cleanly: the extension contract, OAuth 2 security, Docker-based deployment, and calls back into the Headless APIs.

Introduction

Traditional Liferay customizations are frequently deployed as OSGi modules inside the Liferay runtime. For example:

Diagram
Liferay JVM
    |
    +-- MVC Portlet
    +-- Service Builder
    +-- REST Builder
    +-- OSGi Component
    +-- Event Listener

This architecture is powerful, but it creates runtime coupling between the customization and Liferay. A Client Extension provides another integration model. Instead of deploying all custom application logic directly into the Liferay JVM, functionality can run externally and integrate with Liferay through supported interfaces.

The architecture becomes:

Diagram
+-----------------------+
|      Liferay DXP      |
+-----------+-----------+
           |
           | HTTP / OAuth 2 / APIs
           |
           v
+-----------------------+
| External Microservice |
| Java / Python / Node  |
| Go / .NET / etc.      |
+-----------------------+

What is a Client Extension?

A Liferay Client Extension is a mechanism for extending or integrating with Liferay while reducing direct coupling to the portal runtime. Client extensions can support different extension scenarios. Depending on the Liferay version and platform capabilities, examples can include:

  • Custom element integrations
  • Global CSS
  • Global JavaScript
  • Theme CSS
  • Object actions
  • Object validation
  • Workflow-related integrations
  • OAuth applications
  • External microservices

The exact supported types depend on the Liferay release.

What is a Microservice Client Extension?

A Microservice Client Extension is intended for external application logic that needs to participate in a Liferay solution. The service can be developed independently using technologies such as:

  • Java / Spring Boot
  • Python / FastAPI
  • Node.js
  • Go
  • .NET
  • Other HTTP-capable frameworks

For example:

Diagram
Liferay
   |
   +------> FastAPI AI Service
   |
   +------> Spring Boot Payment Service
   |
   +------> Node.js Notification Service
   |
   +------> Python Quantum Service

This allows teams to choose technology according to the workload rather than requiring every feature to execute inside Liferay.

Traditional OSGi vs Microservice Architecture

Consider a custom business operation. In the traditional model:

Diagram
Browser
   |
   v
Liferay
   |
   v
Diagram
OSGi Module
   |
   v
Business Logic

The custom logic runs inside the Liferay JVM. With an external microservice:

Diagram
Browser
   |
   v
Liferay
   |
   +----------------+
                  |
                  v
             Microservice
                  |
                  v
             Business Logic

The application logic executes outside Liferay.

Architectural Comparison

CharacteristicOSGi ModuleMicroservice Client Extension
RuntimeInside Liferay JVMOutside Liferay JVM
TechnologyPrimarily Java/OSGiLanguage/framework inde-
DeploymentLiferay deployment lifecyclependent External/container deployment lifecycle
Failure isolationLowerPotentially stronger
ScalingUsually tied to LiferayCan scale independently
CommunicationJava/OSGi servicesHTTP/API-based
SecurityPortal/OSGi security modelOAuth/API/network security
Upgrade couplingPotentially strongerPotentially reduced

Why Use Microservice Client Extensions?

They are useful when the application requires:

  • Independent deployment
  • Independent scaling
  • Non-Java technologies
  • AI/ML workloads
  • Quantum computing integration
  • Data processing
  • External APIs
  • Long-running computation
  • Specialized libraries
  • Better failure isolation

High-Level Architecture

A typical architecture is:

Diagram
+----------------------+
|        User          |
+----------+-----------+
          |
          v
+----------------------+
|     Liferay DXP      |
|                   |
| Pages                |
| Objects              |
| Workflow             |
| Headless APIs        |
| OAuth 2              |
+----------+-----------+
          |
          | HTTPS
          |
          v
+----------------------+
| Microservice Client  |
| Extension            |
+----------+-----------+
          |
          v
+----------------------+
| Business Service     |
|                   |
| FastAPI              |
| Spring Boot          |
| Node.js              |
| Go                |
Diagram
+----------+-----------+
          |
          v
+----------------------+
| DB / AI / Quantum /  |
| External Systems     |
+----------------------+

Role of client-extension.yaml

A central artifact in a client-extension project is typically:

Code
client-extension.yaml

It describes the client extension and its integration configuration. Conceptually:

YAML
my-microservice:
    name: My Microservice
    type: microservice

The exact schema and properties depend on the Liferay version and client extension type.

Project Structure

A conceptual project structure can look like:

Diagram
my-microservice/
|
+-- client-extension.yaml
|
+-- Dockerfile
|
+-- src/
|   |
|   +-- application code
|
+-- requirements.txt
|
+-- README.md

For Java:

Diagram
my-service/
|
+-- client-extension.yaml
+-- Dockerfile
+-- build.gradle
+-- src/
    +-- main/
       +-- java/

For Python:

Diagram
quantum-service/
|
+-- client-extension.yaml
+-- Dockerfile
+-- requirements.txt
+-- app/
    +-- main.py
    +-- services/
    +-- models/

Example FastAPI Microservice

Consider a simple Python service:

Script
from fastapi import FastAPI

app = FastAPI()

@app.get("/health")
def health():
    return {
       "status": "UP"
    }

@app.post("/api/process")
def process(payload: dict):

    return {
       "success": True,
       "input": payload
    }

The service runs independently from Liferay. For example:

Code
http://microservice:8000

or in production:

Code
https://service.example.com

Containerizing the Microservice

A common deployment strategy is Docker. For the FastAPI example:

Code
FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir \
    -r requirements.txt
Code
COPY . .

CMD [
    "uvicorn",
    "app.main:app",
    "--host",
    "0.0.0.0",
    "--port",
    "8000"
]

Build the image:

Shell
docker build -t my-liferay-service .

Run locally:

Shell
docker run \
    -p 8000:8000 \
    my-liferay-service

Then test:

Shell
curl http://localhost:8000/health

Expected result:

Code
{
    "status": "UP"
}

Client Extension Build

In a Liferay workspace, client extensions are commonly located under:

Code
client-extensions/

For example:

Diagram
liferay-workspace/
|
+-- client-extensions/
|   |
|   +-- my-microservice/
|      |
|       +-- client-extension.yaml
|      +-- ...
|
+-- modules/
+-- themes/
+-- gradle/

A typical Gradle workflow may involve:

Shell
./gradlew build

or building the specific client extension project. On Windows:

Shell
gradlew.bat build

The build packages the client-extension configuration into an artifact that Liferay can deploy.

Deployment Concept

A key distinction is that there are effectively two deployment concerns:

Liferay Configuration + External Service Deployment

The client extension registers/configures the integration with Liferay. The actual microservice runs separately. Conceptually:

Diagram
              BUILD
                |
      +----------+----------+
      |                   |
      v                   v
Client Extension        Microservice
Artifact                Container
      |                   |
      v                   v
    Liferay             Docker/K8s/
                     Cloud Runtime

Deployment Flow

A practical flow can be understood as:

  1. Develop the microservice.
  2. Test the service independently.
  3. Define the client extension.
  4. Configure authentication.
  5. Build the client extension.
  6. Build the service/container.
  7. Deploy the client extension to Liferay.
  8. Deploy the microservice to its runtime.
  9. Configure environment variables and secrets.
  10. Verify connectivity.
  11. Test authentication.
  12. Execute end-to-end integration testing.

Communication Direction

There are two important directions of communication.

Liferay to Microservice

Liferay → Microservice

Examples:

  • Object Action
  • Workflow action
  • Webhook
  • External validation
  • AI inference request

Microservice to Liferay

Microservice → Liferay Headless API

Examples:

  • Read Liferay Objects
  • Update Object entries
  • Retrieve documents
  • Create content
  • Query users
  • Invoke Headless APIs

Many real systems use both directions.

OAuth 2 Authentication

A microservice should generally not call protected Liferay APIs without authentication. OAuth 2 can provide service-to-service authorization. The architecture becomes:

Diagram
+--------------------+
|   Microservice     |
+---------+----------+
         |
         | OAuth 2
         v
+--------------------+
|     Liferay        |
| OAuth Provider     |
+---------+----------+
         |
         v
+--------------------+
| Headless REST APIs |
+--------------------+

Client Credentials Flow

For machine-to-machine communication, a common OAuth pattern is:

Client Credentials Grant

There is no interactive user login. Instead:

Diagram
Microservice
    |
    | client_id
    | client_secret
    v
OAuth Token Endpoint
    |
    | access_token
    v
Microservice
    |
    | Bearer Token
    v
Liferay API

Conceptually:

Client Credentials → Access Token → API Call

Token Request

A conceptual token request is:

HTTP
POST /o/oauth2/token

grant_type=client_credentials
client_id=YOUR_CLIENT_ID
client_secret=YOUR_CLIENT_SECRET

The response can contain:

Code
{
    "access_token": "...",
    "token_type": "Bearer",
    "expires_in": 600
}

The service then sends:

Code
Authorization: Bearer ACCESS_TOKEN

when calling Liferay.

Calling Liferay Headless APIs

Suppose the microservice needs to retrieve Liferay Object entries. Conceptually:

HTTP
GET /o/c/orders/
Authorization: Bearer ACCESS_TOKEN

The response may contain:

Code
{
    "items": [
       {
          "id": 101,
          "orderNumber": "ORD-1001"
       }
    ]
}

Thus:

Microservice → OAuth → Liferay Headless API

Python Example

A simplified Python example is:

Java
import requests

LIFERAY_URL = "https://portal.example.com"

CLIENT_ID = "my-client"
CLIENT_SECRET = "my-secret"

token_response = requests.post(
    f"{LIFERAY_URL}/o/oauth2/token",
    data={
       "grant_type": "client_credentials",
       "client_id": CLIENT_ID,
       "client_secret": CLIENT_SECRET
    }
)

token_response.raise_for_status()

token = token_response.json()["access_token"]

response = requests.get(
    f"{LIFERAY_URL}/o/c/orders/",
    headers={
       "Authorization": f"Bearer {token}"
    }
)

response.raise_for_status()

print(response.json())

Environment Variables

A microservice can use environment variables such as:

Code
LIFERAY_URL
LIFERAY_CLIENT_ID
LIFERAY_CLIENT_SECRET
DATABASE_URL
LOG_LEVEL

Python example:

Java
import os

liferay_url = os.environ["LIFERAY_URL"]

client_id = os.environ["LIFERAY_CLIENT_ID"]

client_secret = os.environ[
    "LIFERAY_CLIENT_SECRET"
]

This separates configuration from application code.

Development vs Production

Development might use:

YAML
Liferay:
http://localhost:8080

Microservice:
http://localhost:8000

Production might use:

YAML
Liferay:
https://portal.company.com

Microservice:
https://api.company.com

The application should therefore avoid hard-coded URLs.

Deployment Using Containers

The external service can be deployed using:

  • Docker
  • Kubernetes
  • Cloud container platforms
  • Virtual machines
  • Managed application platforms

Conceptually:

Diagram
          Internet / Private Network
                  |
      +-------------+-------------+
      |                       |
      v                       v
+-------------+            +---------------+
| Liferay DXP |            | Microservice  |
+-------------+            +-------+-------+
                              |
                              v
                        +-------------+
                        | Database /  |
                        | AI / APIs   |
                        +-------------+

Kubernetes Architecture

For larger deployments:

Diagram
+--------------------------------------+
| Kubernetes Cluster                   |
|                                 |
| +---------------+                    |
| | Service       |                    |
| +-------+-------+                    |
|        |                        |
| +-------+--------+                   |
| | Load Balancer |                   |
| +-------+--------+                   |
|        |                        |
|   +-----+-----+                      |
|   |         |                   |
|   v         v                   |
| +-----+     +-----+                  |
| | Pod |     | Pod |               |
| +-----+     +-----+                  |
|                                 |
+--------------------------------------+
           ^
           |
           | HTTPS
           |
      Liferay DXP

The microservice can scale independently:

1 pod → 5 pods → 20 pods

without necessarily scaling the Liferay runtime itself.

Independent Scaling

Suppose Liferay handles:

1, 000 portal users

while an AI service receives:

50, 000 inference requests

The AI workload may require more compute resources than the portal. With a microservice architecture:

Scale(Liferay)̸ = Scale(AI Service)

Each component can be scaled according to its workload.

Failure Isolation

Suppose an AI service crashes. With tightly embedded application logic:

Application Failure → Possible Portal Impact

With an external microservice:

Microservice Failure̸ ⇒ Liferay JVM Failure

Liferay can remain available and display an appropriate service error or retry later.

Timeouts

External calls must have explicit timeouts. Bad approach:

Code
requests.get(url)

Better:

Code
requests.get(
    url,
    timeout=10
)

Without timeouts, slow external services can consume application resources indefinitely.

Retries

Transient failures may justify retry logic. For example:

Attempt 1 → 1s → Attempt 2 → 2s → Attempt 3

This is an example of exponential backoff. However, retries must be used carefully. A POST operation that creates data should not automatically be repeated unless the operation is designed to be idempotent or otherwise protected against duplication.

Circuit Breaker

If an external service is repeatedly failing, continuing to call it can worsen system instability. A circuit breaker conceptually behaves as:

Closed → Failures → Open → Recovery Test → Closed

This can protect Liferay and the external service during outages.

Health Checks

A microservice should expose a health endpoint. For example:

HTTP
GET /health

Response:

Code
{
    "status": "UP"
}

A more advanced health endpoint might check:

  • Database connectivity
  • Liferay connectivity
  • Model availability
  • Message broker availability
  • Required external APIs

Logging and Observability

A distributed architecture requires strong observability. Useful information includes:

  • Timestamp
  • Request ID
  • Correlation ID
  • Service name
  • HTTP status
  • Response time
  • Error details

For example:

Properties
requestId=abc-123
service=quantum-service
endpoint=/simulate
status=200
duration=840ms

Correlation IDs

A request may cross multiple systems:

Browser → Liferay → Microservice → Database

A correlation ID can follow the request:

Code
X-Correlation-ID: abc-123

Then logs across systems can be associated with the same transaction.

Security Architecture

A secure architecture should consider:

  • HTTPS/TLS
  • OAuth 2
  • Least privilege
  • Secret management
  • Network restrictions
  • Input validation
  • Authentication
  • Authorization
  • Logging
  • Token expiration

The goal is:

Authenticate + Authorize + Encrypt + Validate + Audit

Least Privilege

A microservice should receive only the permissions required for its function. For example, if a service only reads orders:

Permission = Read Orders

not:

Permission = Portal Administrator

This limits the impact of credential compromise.

Example AI Architecture

A useful Liferay architecture is:

Diagram
+---------------------+
| Liferay Portal      |
|                   |
| UI                |
| User Management     |
| Workflow            |
| Objects             |
+----------+----------+
          |
          | REST
          v
+---------------------+
| FastAPI             |
| AI/ML Service       |
+----------+----------+
          |
          v
+---------------------+
| ML Model            |
| PyTorch / TF / etc. |
+---------------------+

This avoids forcing Python machine-learning dependencies into the Liferay JVM.

Example Quantum Architecture

The same architecture works particularly well for quantum services.

Diagram
+------------------------+
| Liferay DXP            |
|                     |
| Assessment Portal      |
| User Management        |
| Workflow               |
+-----------+------------+
           |
           | REST
           v
+------------------------+
| FastAPI Quantum        |
| Microservice           |
+-----------+------------+
           |
     +------+------+
     |           |
     v           v
+---------+     +---------+
| Qiskit  |     | Qulacs  |
+---------+     +---------+
Diagram
     |
     v
+-------------------------+
| Quantum Backend /       |
| Simulator               |
+-------------------------+

This provides a clean separation:

Liferay = Portal + Governance

while:

Microservice = Quantum Computation

Microservice vs Remote App

A useful conceptual distinction is:

MicroserviceRemote UI/App
Primary roleBackend/business logicExternal user interface
InteractionAPI/service callsBrowser-facing application
Typical technologiesFastAPI, Spring Boot, NodeReact, Angular, Vue
UI requiredNoUsually yes

A solution may contain both.

Deployment Pipeline

A CI/CD pipeline can be:

Diagram
Developer
    |
    v
Git Repository
    |
    v
CI Pipeline
    |
    +-------------------+
    |                |
    v                v
Build Client       Build Docker
Extension          Image
    |                |
    v                v
Deploy to          Push to
Liferay            Registry
                     |
                     v
                  Deploy
                     |
                     v
               Microservice

This allows the portal integration and service runtime to have controlled but independent deployment lifecycles.

Versioning

External services should expose versioned APIs. For example:

Code
/api/v1/diagnose
/api/v2/diagnose

instead of relying permanently on:

Code
/diagnose

Versioning makes backward-compatible upgrades easier.

API Contract

The integration between Liferay and a microservice should have a clearly defined contract. For example:

HTTP
POST /api/v1/diagnose

Request:
{
    "patientId": "P10025",
    "imageId": 7812
}

Response:
{
    "reportId": "R-981",
    "prediction": "Normal",
    "confidence": 0.94
}

The contract should define:

  • Endpoint
  • HTTP method
  • Authentication
  • Request schema
  • Response schema
  • Error codes
  • Timeout
  • Version

Common Deployment Problems

Microservice is Unreachable

Check:

  • DNS
  • Service URL
  • Firewall
  • Container port
  • Reverse proxy
  • TLS certificate

401 Unauthorized

Check:

  • Client ID
  • Client secret
  • Access token
  • Token expiration
  • OAuth configuration

403 Forbidden

Authentication may have succeeded, but the service identity may not have sufficient permissions.

Connection Refused

Verify:

Code
host
port
container status
service status
network

Timeout

Check:

  • Service processing time
  • Network latency
  • Downstream systems
  • Timeout configuration

A robust enterprise architecture can be represented as:

Diagram
           +----------------+
           |      User      |
           +-------+--------+
                  |
                  v
           +----------------+
           |  Liferay DXP   |
           +-------+--------+
                  |
          OAuth 2 / HTTPS
                  |
                  v
          +----------------+
          | API / Gateway  |
          +-------+--------+
                 |
       +-----------+-----------+
       |                    |
       v                    v
+---------------+       +---------------+
| Microservice  |       | Microservice  |
| A            |      | B            |
+-------+-------+       +-------+-------+
       |                    |
       v                    v
   Database                AI / External
                        System

Optional enterprise components can include:

  • API gateway
  • Message broker
  • Centralized logging
  • Metrics
  • Distributed tracing
  • Secret manager
  • Kubernetes

Best Practices

For production deployments:

  1. Keep the microservice stateless where practical.
  2. Use HTTPS.
  3. Use OAuth 2 for protected Liferay APIs.
  4. Keep secrets outside source code.
  5. Apply least privilege.
  6. Define explicit HTTP timeouts.
  7. Use retries only where safe.
  8. Use health checks.
  9. Add correlation IDs.
  10. Centralize logs.
  11. Version APIs.
  12. Validate input.
  13. Design idempotent operations where practical.
  14. Monitor latency and failures.
  15. Separate development, test, and production configuration.

Interview Questions

Multiple Choice Questions

Question 1

Where does a Microservice Client Extension’s application logic primarily execute?

A. Inside the browser only

B. Inside the Liferay JVM

C. Outside the Liferay JVM

D. Inside Elasticsearch

Answer: C

Question 2

Which file commonly describes a Liferay client extension?

A. portal-ext.properties

B. client-extension.yaml

C. service.xml

D. web.xml

Answer: B

Question 3

Which technology can be used to implement an external microservice?

A. Spring Boot

B. FastAPI

C. Node.js

D. All of the above

Answer: D

Question 4

Which OAuth flow is commonly suitable for machine-to-machine communication?

A. Client Credentials

B. Interactive password entry on every API call

C. JSP session flow

D. None

Answer: A

Question 5

Which header commonly carries an OAuth access token?

A. Content-Length

B. Host

C. Authorization

D. Accept-Language

Answer: C

Question 6

What is a major benefit of external microservices?

A. They require every service to use Java

B. They can scale independently

C. They eliminate network communication

D. They remove all security requirements

Answer: B

Question 7

Where should production client secrets normally be stored?

A. Public GitHub repository

B. JavaScript source

C. Environment/secret management system

D. HTML page

Answer: C

Question 8

What does HTTP 401 generally indicate?

A. Authentication problem

B. Successful request

C. Database backup

D. Client extension build success

Answer: A

Question 9

What does HTTP 403 generally indicate?

A. Authorization/permission problem

B. DNS success

C. Docker build success

D. Liferay startup completion

Answer: A

Question 10

Why are correlation IDs useful?

A. They increase CPU speed

B. They trace a request across distributed services

C. They replace OAuth

D. They replace TLS

Answer: B

Question 11

Which is generally preferable for a computationally intensive Python AI model?

A. Embedding Python dependencies directly in the Liferay JVM

B. External Python microservice

C. JSP scriptlet

D. Theme CSS

Answer: B

Question 12

Which component provides REST APIs for external services to interact with Liferay resources?

A. Liferay Headless APIs

B. CSS Loader

C. JSP Compiler

D. Theme Builder

Answer: A

Quick Revision

ConceptMeaning
Client ExtensionExternal extension/integration mechanism
MicroserviceIndependently running application service
client-extension.yamlClient extension configuration descriptor
OAuth 2Authorization framework for secured API access
Client CredentialsMachine-to-machine OAuth grant
Headless APIREST API exposed by Liferay
DockerContainer packaging/runtime technology
KubernetesContainer orchestration platform
Health CheckEndpoint indicating service health
Correlation IDIdentifier for tracing distributed requests
Circuit BreakerResilience pattern for failing services

Key Takeaway

The fundamental architecture is:

Liferay DXP ←→ Microservice Client Extension ←→ External Business Logic

Instead of placing every customization inside the Liferay JVM:

Liferay JVM + All Custom Logic

the system can be decomposed into:

Liferay = Portal + Identity + Workflow + Governance

and:

Microservices = Specialized Business/Compute Services

This architecture is particularly useful for applications involving AI/ML, quantum computing, data processing, external enterprise systems, or independently scalable backend services. The production design should emphasize:

API Contract + OAuth 2 + TLS + Secret Management + Observability + Resilience

rather than treating a microservice as simply another HTTP endpoint.

Official Reference

For current, version-specific configuration and deployment details, refer to the official Liferay documentation:

Code
https://learn.liferay.com/w/dxp/development/integrating-microservices/
              using-a-microservice-client-extension

The exact client-extension.yaml schema, supported properties, OAuth configuration, and deployment process should always be verified against the Liferay DXP release used by the target environment.

Prefer to read offline? Download the PDF edition (29 pages).