# Encrypt gateway configs stored in database

To encrypt (and later decrypt) sensitive configuration details (like payment provider credentials) we have to do four things:

* Make sure model implements `CryptedInterface`. The `GatewayConfig` class already does it.
* Generate a cypher key and store it
* Configure our dynamic gateways
* Create a Form Type Extension

First, we have to install an encryption library `defuse/php-encryption`:

```bash
$ composer require defuse/php-encryption:^2
```

### Generate and Store your Cypher Key

Once the library is installed, you should generate a cypher key:

```bash
$ vendor/bin/generate-defuse-key
```

It will output something like this:

```
def00000c794ad36e544b9557c098620e19be5f96529a227d4b22874ce16c9cab2ae90a45b07f20b86349c6e1d892ed042562f86ebb50fbb8b6394b8797c63b12d232db4
```

For storing your cypher key, the best way is to use a environment variable. If your are using [Symfony Dotenv Component](https://symfony.com/doc/current/components/dotenv.html), you can store your cypher key like this:

```dotenv
#.env
PAYUM_CYPHER_KEY=def00000c794ad36e544b9557c098620e19be5f96529a227d4b22874ce16c9cab2ae90a45b07f20b86349c6e1d892ed042562f86ebb50fbb8b6394b8797c63b12d232db4
```

### Configure

Then, you should configure your dynamic gateways:

```diff
#app/config/config.yml

payum:
    dynamic_gateways:
        config_storage: 
            Acme\PaymentBundle\Entity\GatewayConfig: { doctrine: orm }
+        encryption:
+              defuse_secret_key: '%env(PAYUM_CYPHER_KEY)%'
```

### Usage

#### With Sonata Admin

If you are using [Sonata Admin integration](/payum/symfony/configure-payment-in-backend.md#with-sonata-admin), you can stop here because everything is done automatically.

#### The manual way

You should tell to Symfony how to encrypt/decrypt your gateway configuration when you use your `PaypalGatewayConfigType` form type (previously done in [Configure gateway in backend](/payum/symfony/configure-payment-in-backend.md)).

For that, you have two solutions:

1. update your `PaypalGatewayConfigType` form type
2. create a [Form Type Extension](https://symfony.com/doc/current/form/create_form_type_extension.html) that will modify your `PaypalGatewayConfigType` form type

The second solution is better, because if you have a form type for a second gateway (for example [Stripe.js](/payum/readme.md#stripe)), you won't have to duplicate your logic in your `StripeGatewayConfigType` form type.

We will create a `CryptedGatewayConfigTypeExtension` form type extension in the namespace `Acme\PaymentBundle\Form\Extension`. Be sure to follow [this step](https://symfony.com/doc/current/form/create_form_type_extension.html#registering-your-form-type-extension-as-a-service) to register your form type extension as a service.

```php
<?php

declare(strict_types=1);

namespace Acme\PaymentBundle\Form\Extension;

use Acme\PaymentBundle\Form\Type\Payment\PaypalGatewayConfigType;
use Payum\Core\Security\CryptedInterface;
use Payum\Core\Security\CypherInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class CryptedGatewayConfigTypeExtension extends AbstractTypeExtension
{
    private $cypher;

    public function __construct(?CypherInterface $cypher = null)
    {
        $this->cypher = $cypher;
    }

    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        if (null === $this->cypher) {
            return;
        }

        $builder
            // Before set form data, we decrypt the gateway config
            ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
                $gatewayConfig = $event->getData();

                if (!$gatewayConfig instanceof CryptedInterface) {
                    return;
                }

                $gatewayConfig->decrypt($this->cypher);

                $event->setData($gatewayConfig);
            })
            // After submitting the form, we encrypt the gateway back
            ->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
                $gatewayConfig = $event->getData();

                if (!$gatewayConfig instanceof CryptedInterface) {
                    return;
                }

                $gatewayConfig->encrypt($this->cypher);

                $event->setData($gatewayConfig);
            });
    }

    /**
     * {@inheritdoc}
     */
    public function getExtendedTypes(): array
    {
        // The extension will be applied on `PaypalGatewayConfigType` form type.
        // Feel free to add another form types if needed.
        return [PaypalGatewayConfigType::class];
    }
}
```

***

### Supporting Payum

Payum is an MIT-licensed open source project with its ongoing development made possible entirely by the support of community and our customers. If you'd like to join them, please consider:

* [Become a sponsor](https://github.com/sponsors/Payum)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://payum.gitbook.io/payum/symfony/encrypt-gateway-configs-stored-in-database.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
