OAuth
OAuth is a core part of how ldev talks to Liferay.
Many ldev commands work through Liferay APIs rather than through the UI. That includes:
- portal discovery
- portal checks
- resource export and import
- inventory and page inspection
- MCP and agent-friendly API access
That means ldev needs a valid OAuth2 client for the current portal.
The normal user flow
Once the portal is up and the setup wizard is complete, install OAuth once:
ldev oauth install --write-envThat command creates or refreshes the managed OAuth app used by ldev, then writes the read-write client credentials into:
.liferay-cli.local.yml
After that, commands such as these can authenticate directly against the portal APIs:
ldev portal check
ldev portal inventory sites
ldev portal auth token --rawWhere credentials live
For OAuth credentials, the preferred local destination is:
.liferay-cli.local.yml
This file is local-only and should not be committed.
ldev still supports docker/.env as a legacy fallback for some runtime values and older setups, but OAuth credentials written by ldev oauth install --write-env go to .liferay-cli.local.yml.
Resolution order
For the portal URL and OAuth credentials, ldev resolves configuration in this order:
- shell environment variables
.liferay-cli.local.ymldocker/.envas a legacy fallback- built-in defaults
For shared project defaults such as paths, ldev uses:
.liferay-cli.yml.liferay-cli.local.ymlwhen overriding those values locally
Why there are two install paths
ldev oauth install supports two project shapes:
ldev-native: deploy the bundled OAuth installer and invoke its Gogo command directly- Liferay Workspace: deploy the same bundle and bootstrap via a temporary OSGi config
The user-facing contract is the same in both cases:
- install or refresh the managed OAuth app
- verify that the credentials work when possible
- persist local credentials for the CLI
Manual setup for remote environments (no ldev oauth install)
In some remote environments you cannot use ldev oauth install --write-env (for example, no bundle deployment or no Gogo access). In that case, create the OAuth2 app manually in Liferay and pass credentials with global CLI overrides.
1. Create the OAuth2 app in Liferay
In Control Panel, create a new OAuth2 application (client credentials flow):
- grant type: client credentials
- token endpoint auth method: client secret basic (default in most portals)
- keep generated client id and client secret
- set a clear name like
ldev-remote-ops
2. Add required scopes
For typical ldev portal/resource usage, include at least:
Liferay.Headless.Admin.User.everything.readLiferay.Headless.Admin.Site.everything.readLiferay.Data.Engine.REST.everything.readLiferay.Data.Engine.REST.everything.writeLiferay.Headless.Delivery.everything.readLiferay.Headless.Delivery.everything.writeliferay-json-web-services.everything.readliferay-json-web-services.everything.writeLiferay.Headless.Discovery.API.everything.readLiferay.Headless.Discovery.OpenAPI.everything.read
If your security policy requires least privilege, start with read scopes only and add write scopes only for commands that modify resources.
3. Store credentials securely in the execution host
Prefer environment variables over inline secrets:
export LIFERAY_REMOTE_URL=https://portal.example.com
export LIFERAY_REMOTE_CLIENT_ID=ldev-remote-ops
export LIFERAY_REMOTE_CLIENT_SECRET='***'4. Run ldev using namespace overrides
Attach the connection options to ldev portal or ldev resource before the concrete subcommand:
ldev portal \
--liferay-url "$LIFERAY_REMOTE_URL" \
--liferay-client-id "$LIFERAY_REMOTE_CLIENT_ID" \
--liferay-client-secret-env LIFERAY_REMOTE_CLIENT_SECRET \
check --jsonldev portal \
--liferay-url "$LIFERAY_REMOTE_URL" \
--liferay-client-id "$LIFERAY_REMOTE_CLIENT_ID" \
--liferay-client-secret-env LIFERAY_REMOTE_CLIENT_SECRET \
inventory sites --json5. Validate before running write operations
Run this sequence first:
ldev portal --liferay-url "$LIFERAY_REMOTE_URL" --liferay-client-id "$LIFERAY_REMOTE_CLIENT_ID" --liferay-client-secret-env LIFERAY_REMOTE_CLIENT_SECRET check --json
ldev portal --liferay-url "$LIFERAY_REMOTE_URL" --liferay-client-id "$LIFERAY_REMOTE_CLIENT_ID" --liferay-client-secret-env LIFERAY_REMOTE_CLIENT_SECRET inventory sites --jsonIf those commands fail with auth/scope errors, update the OAuth app scopes and retry.
When OAuth is not ready yet
If the portal setup wizard is not complete, or the local portal is not reachable yet, OAuth-based commands will fail or stay pending.
Start with:
ldev doctor
ldev oauth install --write-env
ldev portal checkIf that still fails, see Troubleshooting.