Created on 24 July 2025, 10 days ago

Problem/Motivation

The key module is a dependency throughout the Drupal ecosystem, making a new major version more difficult to adopt than most modules. Bringing in new API features only into 2.0 would make compatibility with other downstream modules incompatible. Thus we need to be careful about what the new version of Key is and isn't.

New Key APIs in 8.x-1.x

In order to smooth the transition between 1.x and 2.x, new functionality should be brought into the existing version, with functionality we wish to remove becoming deprecated in 1.x, similar to core. Modules using the new APIs should be able to declare compatibility with both major versions of Key, allowing other modules that are not maintained to still work on sites. By being compatible with both versions and having the APIs in 8.x-1.x, downstream modules shouldn't need to make a new major version.

What changes in 2.x?

(This list subject to change)
* Drupal 10.5 will be the minimum version πŸ“Œ Support PHP attributes for KeyProvider plugins Active
* Decouple existing plugin system: #3168120: Improve Separation of Plug-in Concerns (Keys, KeyTypes, KeyInputs, and KeyProviders) β†’
* Decouple UI from the API

Data model changes

The biggest change is how the plugin system will work. See below:

New Value Object: KeyValue

When loading a key either directly via the key entity or via a key resolver, it should pass back a KeyValueInterface compatible object. In 8.x-1.x, both the Key entity and KeyValue objects are compatible with KeyValueInterface. However with 2.x, the Key->getKeyValue, which delegates to KeyProvider->getKeyValue method, will pass back a KeyValueInterface instead of simply a string. That sets up basic pseudo code like this:

MyModule->clientRequest() {
  // Get the key ID from the module's API key select dropdown in config.
  $key_id = $myModuleConfigFactory->get('key')
  // Use the key resolver service to fetch the appropriate Key for my given $key_id.
  $key = $keyResolverService->resolve($key_id)
  // Get the actual KeyValue. Todo: KeyTypes could change the format. Decide how we want that to work.
  GuzzleClient->request(POST, blahblah, $key->getKeyValue())
}

KeyProvider: Plugin for accessing data

The purpose of the KeyProvider is to connect Key with a datasource. This data source might be config, state, env variables, a file, or a 3rd party service.

Deprecated methods / properties:
'obscureKeyValue' --> This method should be in the UI module and has nothing to do with the key API or provider.
$key_value in KeyProvider class --> This is also UI specific. Need to decide how providers optionally alter the UI.

The provider doesn't do anything else. It passes the raw data back compatible with KeyValueInterface

KeyTypes: Plugin for data formats

This plugin takes the raw data from a KeyProvider and formats it in a way that a consuming module can use. For instance, if its a simple API key, it'll simply return a string. If its an encrypted value, it'd take the raw data from the provider, decrypt it, and pass it to the consuming module.

Key entity is an optional layer upon the key API

Historically, all keys are managed by a Key entity. Instead, Key entity is now split from the Key module and available within Key UI. The Key entity is a union between 'KeyInput', 'KeyType', and 'KeyProvider', all three of which are independent of each other.

This allows services (like Pantheon, Acquia, Amazee, etc) to create their own modules to automatically configure their Keys. So if you're hosted on Acquia, and we have a key service or environment variable containing the keys, the 'api key' no longer needs to exist as a config option, it will just get the hardcoded key_id, which can be overridden via the resolver. Alternatively, if you're using a shared third party module (IE: Google Tag) that supports Key, a hosting provider can form_alter the module's key selection config to autoselect that hosting provider's key, assuming you have thier support module installed (like Acquia Connector)

KeyInput: Change to become a trait?

KeyInput is for Forms and has no relevance to the actual stored keys, and is only needed for Key entities using the UI. Instead of a plugin, make KeyInput a trait for KeyTypes if the same Input could be used in different types.

I'm sure there is more to come here, but wanted to lay out the overarching ideas for 2.0

🌱 Plan
Status

Active

Version

2.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States japerry KVUO

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024