diff --git a/.gitignore b/.gitignore index 9784da828..b6b7deb71 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ /docs/changelog.md /docs/changelog-*.md /docs/cache/ -/docs/*/cache/ \ No newline at end of file +/docs/*/cache/ +.codex \ No newline at end of file diff --git a/app/helpers/Content/Category/IntegrateCategory.php b/app/helpers/Content/Category/IntegrateCategory.php index d0fa67d37..7d0f01989 100644 --- a/app/helpers/Content/Category/IntegrateCategory.php +++ b/app/helpers/Content/Category/IntegrateCategory.php @@ -31,6 +31,7 @@ public function getItems() new Guide('reporting-introduction'), new RemoteLink('Integrations', 'https://matomo.org/integrate/'), new Guide('tagmanager/introduction'), + new Guide('oauth2'), new Guide('ab-tests'), new Guide('heatmap-session-recording'), new Guide('crash-analytics'), diff --git a/docs/5.x/authentication-in-depth.md b/docs/5.x/authentication-in-depth.md index 717aeab2c..f044d92b1 100644 --- a/docs/5.x/authentication-in-depth.md +++ b/docs/5.x/authentication-in-depth.md @@ -9,6 +9,7 @@ There are different ways a user can authenticate in Matomo: * Using username / password and the regular login form. * The [logme](https://matomo.org/faq/how-to/faq_30/) feature can be used to log someone in using username and password in the URL. * Using a `token_auth` URL parameter for our HTTP API's and widgets. +* Using OAuth 2.0 bearer tokens for external applications when the OAuth 2.0 plugin is installed. ## Username and password login @@ -64,6 +65,14 @@ When there is a request and we can use a session, then Matomo [checks first if t * When a `token_auth` parameter is set by us, then we usually POST the token_auth. This is for security reasons so the token_auth won't appear in server logs. Otherwise a sysadmin could see the token in the logs and do all sort of actions on behalf of another user. * Remember that users should not share the token_auth as it is the same as them sharing their username/password. +## OAuth 2.0 + +If the [OAuth 2.0](/guides/oauth2) plugin is installed, external applications can authenticate against Matomo using OAuth 2.0 access tokens. + +This is mainly useful when integrating third-party or custom applications that should not receive a long-lived `token_auth`. In that case the application first obtains an access token through the plugin's OAuth 2.0 endpoints and then sends that token as a bearer token when calling supported Matomo APIs. + +Depending on the application type, you would typically use either the Authorization Code flow with PKCE or the Client Credentials flow. For the integration flow and request examples, see the [OAuth 2.0 guides](/guides/oauth2). + ## Alternative login plugins It is possible to write plugins that provide [alternative Login methods](https://plugins.matomo.org/search?query=login&post_type=product) like [LDAP](https://plugins.matomo.org/LoginLdap), [SAML](https://plugins.matomo.org/LoginSaml), etc. diff --git a/docs/5.x/oauth2.md b/docs/5.x/oauth2.md new file mode 100644 index 000000000..f33813921 --- /dev/null +++ b/docs/5.x/oauth2.md @@ -0,0 +1,20 @@ +--- +category: Integrate +subGuides: + - oauth2/setup + - oauth2/authorization-code + - oauth2/client-credentials + - oauth2/api-usage + - oauth2/faq +--- +# OAuth 2.0 + +This section contains guides that will help you authenticate external applications against Matomo using OAuth 2.0. + +The **OAuth 2.0** plugin adds a first-party OAuth 2.0 Authorization Server to Matomo. It allows external applications to access Matomo APIs using OAuth 2.0 access tokens instead of sending a `token_auth`. + +The plugin supports the **Authorization Code** flow with **PKCE**, **Client Credentials**, and **Refresh Token** support. Applications authenticate with bearer tokens and can be limited to the scopes granted to each OAuth client. + +OAuth 2.0 clients can be managed in Matomo under **Administration => Platform => OAuth 2.0**. In Matomo Cloud, this screen is available under **Administration => Export => OAuth 2.0**. From there you can create, edit, pause, resume, or delete clients, and rotate secrets for confidential clients. + +If you are looking for general API authentication details, also see [Authentication In Depth](/guides/authentication-in-depth) and [Querying the Reporting API](/guides/querying-the-reporting-api). diff --git a/docs/5.x/oauth2/api-usage.md b/docs/5.x/oauth2/api-usage.md new file mode 100644 index 000000000..232c6d2b2 --- /dev/null +++ b/docs/5.x/oauth2/api-usage.md @@ -0,0 +1,38 @@ +--- +category: Integrate +title: OAuth 2.0 API Usage +--- +# Calling Matomo APIs with OAuth 2.0 + +Once your application has obtained an access token, it can call Matomo APIs using the `Authorization` header. + +```text +Authorization: Bearer ACCESS_TOKEN +``` + +## Example API request + +```bash +curl 'https://matomo.example.com/index.php' \ + -H 'Authorization: Bearer ACCESS_TOKEN' \ + -d 'module=API' \ + -d 'method=VisitsSummary.get' \ + -d 'idSite=1' \ + -d 'period=day' \ + -d 'date=today' \ + -d 'format=json' +``` + +## OAuth 2.0 compared to `token_auth` + +By default, many Matomo API guides use `token_auth` examples because `token_auth` is available in every Matomo installation. + +When the OAuth 2.0 plugin is installed, external applications can use OAuth 2.0 bearer tokens instead. This avoids sharing a long-lived auth token with the external application, lets you choose a grant type that matches the integration, and makes it easier to limit and revoke access without affecting other applications. + +If you are integrating a backend service with no user interaction, the Client Credentials flow is usually the best fit. If your application acts on behalf of a user, use the Authorization Code flow. + +## Notes + +* Use HTTPS whenever you send access tokens. +* The plugin currently allows only one scope per request. +* Keep using the standard `token_auth` flow in integrations where the OAuth 2.0 plugin is not installed. diff --git a/docs/5.x/oauth2/authorization-code.md b/docs/5.x/oauth2/authorization-code.md new file mode 100644 index 000000000..67de0da03 --- /dev/null +++ b/docs/5.x/oauth2/authorization-code.md @@ -0,0 +1,140 @@ +--- +category: Integrate +title: OAuth 2.0 Authorization Code Flow +--- +# OAuth 2.0 Authorization Code Flow + +Use the Authorization Code flow when your application acts on behalf of a Matomo user. + +## Flow overview + +The Authorization Code flow works like this: + +1. Your application redirects the user to the Matomo authorization endpoint. +2. The user logs in, reviews the requested permissions, and approves access. +3. Matomo redirects back with an authorization `code`. +4. Your application exchanges the code for an access token. +5. Your application calls Matomo APIs using `Authorization: Bearer ACCESS_TOKEN`. + +## PKCE for public clients + +Public clients should use PKCE. PKCE requires a `code_verifier` and a derived `code_challenge`. + +Example values: + +```text +code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk +code_challenge = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM +``` + +Where: + +```text +code_challenge = BASE64URL(SHA256(code_verifier)) +``` + +## Redirect the user to the authorization endpoint + +### Public client with PKCE + +```text +https://matomo.example.com/index.php?module=OAuth2&action=authorize +&response_type=code +&client_id=analytics_app +&redirect_uri=https://example-app.com/oauth/callback +&scope=matomo:read +&state=abc123 +&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM +&code_challenge_method=S256 +``` + +### Confidential client + +```text +https://matomo.example.com/index.php?module=OAuth2&action=authorize +&response_type=code +&client_id=analytics_app +&redirect_uri=https://example-app.com/oauth/callback +&scope=matomo:read +&state=abc123 +``` + +The user will: + +1. Log in to Matomo. +2. Review the requested permissions. +3. Click **Allow**. + +After approval, Matomo redirects back to your application: + +```text +https://example-app.com/oauth/callback?code=AUTHORIZATION_CODE&state=abc123 +``` + +## Exchange the authorization code for tokens + +The requested scope needs to match the client configuration. At the time of writing, the plugin allows only one scope per request. + +### PKCE token request + +```bash +curl -X POST 'https://matomo.example.com/index.php?module=OAuth2&action=token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=authorization_code' \ + -d 'client_id=analytics_app' \ + -d 'redirect_uri=https://example-app.com/oauth/callback' \ + -d 'code=AUTHORIZATION_CODE' \ + -d 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' +``` + +### Confidential client token request + +```bash +curl -X POST 'https://matomo.example.com/index.php?module=OAuth2&action=token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=authorization_code' \ + -d 'client_id=analytics_app' \ + -d 'client_secret=7fa9c0f81b8b4a12' \ + -d 'redirect_uri=https://example-app.com/oauth/callback' \ + -d 'code=AUTHORIZATION_CODE' +``` + +## Example token response + +```json +{ + "token_type": "Bearer", + "expires_in": 3600, + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "refresh_token": "def50200a1b9" +} +``` + +## Refresh an access token + +Use a refresh token to obtain a new access token. + +### Public client + +```bash +curl -X POST 'https://matomo.example.com/index.php?module=OAuth2&action=token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=refresh_token' \ + -d 'client_id=analytics_app' \ + -d 'refresh_token=def50200a1b9' +``` + +### Confidential client + +```bash +curl -X POST 'https://matomo.example.com/index.php?module=OAuth2&action=token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=refresh_token' \ + -d 'client_id=analytics_app' \ + -d 'client_secret=7fa9c0f81b8b4a12' \ + -d 'refresh_token=def50200a1b9' +``` + +## What to read next + +Once you have an access token, see [Calling Matomo APIs with OAuth 2.0](/guides/oauth2/api-usage). diff --git a/docs/5.x/oauth2/client-credentials.md b/docs/5.x/oauth2/client-credentials.md new file mode 100644 index 000000000..842e1010d --- /dev/null +++ b/docs/5.x/oauth2/client-credentials.md @@ -0,0 +1,42 @@ +--- +category: Integrate +title: OAuth 2.0 Client Credentials Flow +--- +# OAuth 2.0 Client Credentials Flow + +Use the Client Credentials flow when a backend service needs to access Matomo APIs without user interaction. + +Typical examples include: + +* Internal analytics dashboards +* Scheduled data exports +* Backend integrations + +## Request an access token + +```bash +curl -X POST 'https://matomo.example.com/index.php?module=OAuth2&action=token' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d 'grant_type=client_credentials' \ + -d 'client_id=analytics_app' \ + -d 'client_secret=7fa9c0f81b8b4a12' \ + -d 'scope=matomo:read' +``` + +## Example token response + +```json +{ + "token_type": "Bearer", + "expires_in": 3600, + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." +} +``` + +Depending on your client configuration, a refresh token may also be available through the token endpoint for supported grant types. + +## When to use this flow + +Use this flow for trusted server-side applications that need server-to-server access and can keep credentials secret. + +If the application needs a user to log in and approve access, use the [Authorization Code flow](/guides/oauth2/authorization-code) instead. diff --git a/docs/5.x/oauth2/faq.md b/docs/5.x/oauth2/faq.md new file mode 100644 index 000000000..c37ff6318 --- /dev/null +++ b/docs/5.x/oauth2/faq.md @@ -0,0 +1,67 @@ +--- +category: Integrate +title: OAuth 2.0 Developer FAQ +--- +# OAuth 2.0 Developer FAQ + +## Which grant types are supported? + +The plugin supports: + +* Authorization Code with PKCE +* Client Credentials +* Refresh Token + +## Which scopes are available? + +The plugin provides these scopes: + +* `matomo:read` +* `matomo:write` +* `matomo:admin` +* `matomo:superuser` + +See the [permissions guide](/guides/permissions) for more information. + +At the time of writing, only one scope can be requested at a time. + +## When should I use a public client? + +Use a public client when your application cannot safely store a client secret, for example in a browser or mobile app. Public clients should use PKCE. + +## When should I use a confidential client? + +Use a confidential client when your application runs on a trusted backend and can safely protect the client secret. + +## Where do I manage OAuth clients? + +Use one of these screens: + +```text +Administration => Platform => OAuth2 (Matomo On-Premise) +Administration => Export => OAuth2 (Matomo Cloud) +``` + +## Which endpoints does the plugin expose? + +The plugin exposes these endpoints: + +* `/index.php?module=OAuth2&action=authorize` +* `/index.php?module=OAuth2&action=token` + +Optional cleaner routes can also be configured: + +* `/oauth2/authorize` +* `/oauth2/token` + +## When is a client secret shown? + +For confidential clients, the client secret is shown in full only when the client is created or when the secret is rotated. After that, the secret is masked in the UI. + +## Can I rotate a client secret? + +Yes. Confidential clients support secret rotation from the edit screen. Rotate the secret if you need a new value or if the existing one may have been exposed. + +## Can I still use `token_auth`? + +Yes. The OAuth 2.0 plugin adds an alternative authentication method for external applications. Existing `token_auth` based integrations continue to be relevant for Matomo installations where the plugin is not enabled. diff --git a/docs/5.x/oauth2/setup.md b/docs/5.x/oauth2/setup.md new file mode 100644 index 000000000..e0f26f6c7 --- /dev/null +++ b/docs/5.x/oauth2/setup.md @@ -0,0 +1,89 @@ +--- +category: Integrate +title: OAuth 2.0 Setup +--- +# Setting up OAuth 2.0 + +In this guide you will learn how to configure an OAuth client so an external application can request access tokens for Matomo. + +## What the OAuth 2.0 plugin provides + +The plugin adds a first-party OAuth 2.0 Authorization Server to Matomo. Once enabled, applications can authenticate against Matomo using bearer tokens instead of sharing a permanent `token_auth`. + +The plugin supports these grant types: + +* Authorization Code with PKCE +* Client Credentials +* Refresh Token + +The plugin currently supports these scopes: + +* `matomo:read` +* `matomo:write` +* `matomo:admin` +* `matomo:superuser` + +See the [permissions guide](/guides/permissions) for more information. + +Access tokens are sent as bearer tokens when calling Matomo APIs. The plugin uses RSA keys to sign JWT access tokens. + +## OAuth 2.0 endpoints + +Matomo exposes these OAuth 2.0 endpoints: + +| Endpoint | Description | +|--------|-------------| +| `/index.php?module=OAuth2&action=authorize` | Authorization endpoint | +| `/index.php?module=OAuth2&action=token` | Token endpoint | + +Optional cleaner routes can also be configured: + +```text +/oauth2/authorize +/oauth2/token +``` + +## Create an OAuth client + +Navigate to one of the following screens: + +```text +Administration => Platform => OAuth2 (Matomo On-Premise) +Administration => Export => OAuth2 (Matomo Cloud) +``` + +Create a client and configure: + +* The client type +* The allowed grant types +* The allowed scopes +* The redirect URI for the Authorization Code flow + +From the client list, you can pause or resume a client, open it for editing, or delete it. For confidential clients, secret rotation is available from the edit screen. + +You can create either of these client types: + +* **Confidential** clients, which use a client secret +* **Public** clients, which do not use a client secret and should use PKCE + +Client secrets are shown in full only when a confidential client is created or when its secret is rotated. After that, the secret is masked and you need to rotate it again if you want a new value. + +Example client: + +```text +Client ID: analytics_app +Client Secret: 7fa9c0f81b8b4a12 +Redirect URI: https://example-app.com/oauth/callback +``` + +## Choosing the right client type + +Use a **public** client when your application cannot safely store a client secret, for example in a browser-based or mobile application. These clients should use PKCE. + +Use a **confidential** client when your application runs on a trusted backend and can safely keep the client secret private. + +At the time of writing, the plugin allows only one scope per request and the requested scope needs to match the client configuration. + +## What to read next + +Once your client is configured, continue with the [Authorization Code guide](/guides/oauth2/authorization-code) or the [Client Credentials guide](/guides/oauth2/client-credentials). diff --git a/docs/5.x/querying-the-reporting-api.md b/docs/5.x/querying-the-reporting-api.md index c6a6b5e98..db6e15fe2 100644 --- a/docs/5.x/querying-the-reporting-api.md +++ b/docs/5.x/querying-the-reporting-api.md @@ -17,6 +17,8 @@ If you want to request data in any language (PHP, Python, Ruby, ASP, C++, Java, If the API call requires the token_auth and the HTTP request is sent over untrusted networks, we highly advise that you use an encrypted request. Otherwise, your token\_auth is exposed to eavesdroppers. This can be done by using https instead of http. +If the [OAuth 2.0](/guides/oauth2) plugin is installed, external applications can also authenticate using OAuth 2.0 bearer tokens instead of sending a `token_auth`. The examples below continue to use `token_auth` because it is available in every Matomo installation. + You can, for example, get the list of countries where most of your visitors in the current month are from. Here is an example in PHP: ```php