diff --git a/composer.json b/composer.json index 7e8c9a2..d2441cf 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "drupal/core-recipe-unpack": "^11.3", "drupal/core-recommended": "^11.3", "drupal/gin": "^5.0", + "drupal/key_auth": "^2.2", "drupal/paragraphs": "^1.20", "drupal/pathauto": "^1.14", "drupal/toolbar_menu": "^3.1", diff --git a/composer.lock b/composer.lock index 26ea5ea..16fb213 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "08941ae50f4e9aaeb1b8a43d0198e234", + "content-hash": "4c42726cf12192612517c99cd8c9dc3b", "packages": [ { "name": "asm89/stack-cors", @@ -1615,6 +1615,67 @@ } ] }, + { + "name": "drupal/key_auth", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://git.drupalcode.org/project/key_auth.git", + "reference": "2.2.0" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/key_auth-2.2.0.zip", + "reference": "2.2.0", + "shasum": "b76e247d974d69199c55f551850bb2b0feb15a36" + }, + "require": { + "drupal/core": "^9.5 || ^10 || ^11" + }, + "type": "drupal-module", + "extra": { + "drupal": { + "version": "2.2.0", + "datestamp": "1722170641", + "security-coverage": { + "status": "covered", + "message": "Covered by Drupal's security advisory policy" + } + } + }, + "notification-url": "https://packages.drupal.org/8/downloads", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "Rajeshreeputra Pravin Dhondiba Gaikwad", + "homepage": "https://www.drupal.org/u/Rajeshreeputra", + "role": "Maintainer" + }, + { + "name": "Mike Stefanello", + "homepage": "https://www.drupal.org/u/mstef", + "role": "Maintainer" + }, + { + "name": "Dan Bryant", + "homepage": "https://www.drupal.org/u/perfectcube", + "role": "Maintainer" + }, + { + "name": "Ganesh Suryawanshi", + "homepage": "https://www.drupal.org/u/ganeshsurya11", + "role": "Maintainer" + } + ], + "description": "Provides simple key-based authentication on a per-user basis similar to basic_auth but without requiring usernames or passwords.", + "homepage": "https://www.drupal.org/project/key_auth", + "support": { + "source": "https://git.drupalcode.org/project/key_auth", + "issues": "https://www.drupal.org/project/issues/key_auth" + } + }, { "name": "drupal/paragraphs", "version": "1.20.0", diff --git a/config/sync/core.extension.yml b/config/sync/core.extension.yml index 17932f2..d53d380 100644 --- a/config/sync/core.extension.yml +++ b/config/sync/core.extension.yml @@ -29,6 +29,7 @@ module: history: 0 image: 0 jsonapi: 0 + key_auth: 0 link: 0 media: 0 media_library: 0 diff --git a/config/sync/key_auth.settings.yml b/config/sync/key_auth.settings.yml new file mode 100644 index 0000000..42c4be7 --- /dev/null +++ b/config/sync/key_auth.settings.yml @@ -0,0 +1,8 @@ +_core: + default_config_hash: 7TOBIjg0aUb-QTF-rzY438_QpTprS-F8OIYTROB2iGc +auto_generate_keys: true +key_length: 32 +param_name: api-key +detection_methods: + - header + - query diff --git a/config/sync/system.action.user_add_role_action.api_consumer.yml b/config/sync/system.action.user_add_role_action.api_consumer.yml new file mode 100644 index 0000000..3cb2189 --- /dev/null +++ b/config/sync/system.action.user_add_role_action.api_consumer.yml @@ -0,0 +1,14 @@ +uuid: f4f9a276-7b81-4268-a1d7-659de4392c6a +langcode: en +status: true +dependencies: + config: + - user.role.api_consumer + module: + - user +id: user_add_role_action.api_consumer +label: 'Add the api_consumer role to the selected user(s)' +type: user +plugin: user_add_role_action +configuration: + rid: api_consumer diff --git a/config/sync/system.action.user_remove_role_action.api_consumer.yml b/config/sync/system.action.user_remove_role_action.api_consumer.yml new file mode 100644 index 0000000..1902f4e --- /dev/null +++ b/config/sync/system.action.user_remove_role_action.api_consumer.yml @@ -0,0 +1,14 @@ +uuid: 62a1836a-cbda-4a02-b9e0-fefa3bbe0b2e +langcode: en +status: true +dependencies: + config: + - user.role.api_consumer + module: + - user +id: user_remove_role_action.api_consumer +label: 'Remove the api_consumer role from the selected user(s)' +type: user +plugin: user_remove_role_action +configuration: + rid: api_consumer diff --git a/config/sync/user.role.api_consumer.yml b/config/sync/user.role.api_consumer.yml new file mode 100644 index 0000000..c040a43 --- /dev/null +++ b/config/sync/user.role.api_consumer.yml @@ -0,0 +1,12 @@ +uuid: c0f50899-5b00-46ac-bae8-9071814edaf2 +langcode: en +status: true +dependencies: + module: + - system +id: api_consumer +label: api_consumer +weight: 6 +is_admin: false +permissions: + - 'access content' diff --git a/docs/issues-plans/issue-74-php-oop.md b/docs/issues-plans/issue-74-php-oop.md index 392d338..9b5fc31 100644 --- a/docs/issues-plans/issue-74-php-oop.md +++ b/docs/issues-plans/issue-74-php-oop.md @@ -2,8 +2,8 @@ issue: 74 title: "[Study] PHP Object-Oriented Programming — Coursera course" branch: n/a — external study track, no branch required -status: in-progress -last_updated: 04-10-2026 +status: closed +last_updated: 05-18-2026 --- # Issue #74 — PHP Object-Oriented Programming — Coursera course diff --git a/docs/issues-plans/issue-90-key-auth.md b/docs/issues-plans/issue-90-key-auth.md new file mode 100644 index 0000000..0575bcb --- /dev/null +++ b/docs/issues-plans/issue-90-key-auth.md @@ -0,0 +1,47 @@ +--- +issue: 90 +title: "[Back-End] Key Auth — API key authentication for JSON:API endpoints" +branch: feat/key-auth-90-api-key-authentication-jsonapi +status: closed +last_updated: 05-19-2026 +--- + +# Issue #90 — [Back-End] Key Auth — API key authentication for JSON:API endpoints + +## Objective +Install and configure `drupal/key_auth` to protect JSON:API endpoints with API key authentication. Covers the simplest machine-to-machine auth pattern in Drupal — no token expiration, no OAuth handshake — suitable for trusted integrations such as inventory sync or external product feeds for Waggy's e-commerce backend. + +## Scope +- Install `drupal/key_auth` via Composer and enable the module +- Understand how key_auth plugs into Drupal's authentication provider system +- Create a dedicated API user, assign an appropriate role with minimal JSON:API permissions +- Generate and assign an API key to that user +- Configure JSON:API to accept (or require) the `X-API-Key` header +- Test authenticated requests via curl / REST client: + - GET with valid `X-API-Key` → 200 with data + - GET without header → 401 / 403 + - GET with invalid key → 401 / 403 +- Export config after setup (`ddev drush cex`) +- Document: API key auth vs OAuth Client Credentials — when to use each + +## Status +> Atualizado em: 05-18-2026 + +- [ ] Install `drupal/key_auth` and enable module +- [ ] Understand key_auth authentication provider plugin +- [ ] Create API user + role with minimal JSON:API read permissions +- [ ] Generate and assign API key to user +- [ ] Configure JSON:API endpoint protection +- [ ] Test: valid key → 200 +- [ ] Test: missing key → 401/403 +- [ ] Test: invalid key → 401/403 +- [ ] Export config +- [ ] Document: API key vs OAuth Client Credentials + +## Notes +- Module: `drupal/key_auth` — implements `AuthenticationProviderInterface`, reads `X-API-Key` request header +- API keys are stored as a field on the Drupal user entity — each user gets one key +- JSON:API is already enabled in the project (used for product listing in issue #5) +- Waggy context: relevant for an inventory sync integration between Waggy's storefront and a warehouse system +- Key reference: `web/modules/contrib/key_auth/src/Authentication/Provider/KeyAuth.php` +- After this issue, JWT (#87) covers the same machine-to-machine use case with token expiration and claims — good comparison point