Repository: cal-itp/benefits

Issue:
Add text fields to the `EligibilityVerifier` model to hold scope/claims info
We need two additional text fields on the `EligibilityVerifier` to hold configuration data for that verifier when they require authentication.

* [ ] `auth_scope` - Optional text field containing the additional scope(s) (space separated) to send (we always send `openid`)
* [ ] `auth_claim` - Optional text field containing the claim to validate


Discussion:

Resolving patch:
diff --git a/benefits/core/migrations/0001_initial.py b/benefits/core/migrations/0001_initial.py
--- a/benefits/core/migrations/0001_initial.py
+++ b/benefits/core/migrations/0001_initial.py
@@ -1,4 +1,7 @@
+# Generated by Django 3.2.13 on 2022-06-13 23:20
+
 from django.db import migrations, models
+import django.db.models.deletion
 
 
 class Migration(migrations.Migration):
@@ -9,48 +12,38 @@ class Migration(migrations.Migration):
 
     operations = [
         migrations.CreateModel(
-            name="EligibilityType",
-            fields=[
-                ("id", models.AutoField(primary_key=True, serialize=False, verbose_name="ID")),
-                ("name", models.TextField()),
-                ("label", models.TextField()),
-                ("group_id", models.TextField()),
-            ],
-        ),
-        migrations.CreateModel(
-            name="PemData",
+            name="AuthProvider",
             fields=[
                 ("id", models.AutoField(primary_key=True, serialize=False)),
-                ("text", models.TextField(help_text="The data in utf-8 encoded PEM text format.")),
-                ("label", models.TextField(help_text="Human description of the PEM data.")),
+                ("sign_in_button_label", models.TextField()),
+                ("sign_out_button_label", models.TextField()),
             ],
         ),
         migrations.CreateModel(
-            name="AuthProvider",
+            name="EligibilityType",
             fields=[
                 ("id", models.AutoField(primary_key=True, serialize=False)),
-                ("sign_in_button_label", models.TextField()),
-                ("sign_out_button_label", models.TextField()),
+                ("name", models.TextField()),
+                ("label", models.TextField()),
+                ("group_id", models.TextField()),
             ],
         ),
         migrations.CreateModel(
             name="EligibilityVerifier",
             fields=[
-                ("id", models.AutoField(primary_key=True, serialize=False, verbose_name="ID")),
+                ("id", models.AutoField(primary_key=True, serialize=False)),
                 ("name", models.TextField()),
                 ("api_url", models.TextField()),
                 ("api_auth_header", models.TextField()),
                 ("api_auth_key", models.TextField()),
-                # fmt: off
-                ("form_sub_pattern", models.TextField(help_text="A regular expression used to validate the 'sub' API field before sending to this verifier", null=True)),  # noqa: E501
-                ("form_name_max_length", models.PositiveSmallIntegerField(help_text="The maximum length accepted for the 'name' API field before sending to this verifier", null=True)),  # noqa: E501
-                ("public_key", models.ForeignKey(help_text="The Verifier's public key, used to encrypt requests targeted at this Verifier and to verify signed responses from this verifier.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
-                ("jwe_cek_enc", models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode")),  # noqa: E501
+                (
+                    "jwe_cek_enc",
+                    models.TextField(help_text="The JWE-compatible Content Encryption Key (CEK) key-length and mode"),
+                ),
                 ("jwe_encryption_alg", models.TextField(help_text="The JWE-compatible encryption algorithm")),
-                ("auth_provider", models.ForeignKey(null=True, on_delete=models.deletion.PROTECT, to="core.authprovider")),
-                # fmt: on
                 ("jws_signing_alg", models.TextField(help_text="The JWS-compatible signing algorithm")),
-                ("eligibility_types", models.ManyToManyField(to="core.EligibilityType")),
+                ("auth_scope", models.TextField(null=True)),
+                ("auth_claim", models.TextField(null=True)),
                 ("selection_label", models.TextField()),
                 ("selection_label_description", models.TextField(null=True)),
                 ("start_content_title", models.TextField()),
@@ -62,17 +55,36 @@ class Migration(migrations.Migration):
                 ("form_blurb", models.TextField()),
                 ("form_sub_label", models.TextField()),
                 ("form_sub_placeholder", models.TextField()),
+                (
+                    "form_sub_pattern",
+                    models.TextField(
+                        help_text="A regular expression used to validate the 'sub' API field before sending to this verifier",
+                        null=True,
+                    ),
+                ),
                 ("form_name_label", models.TextField()),
                 ("form_name_placeholder", models.TextField()),
+                (
+                    "form_name_max_length",
+                    models.PositiveSmallIntegerField(
+                        help_text="The maximum length accepted for the 'name' API field before sending to this verifier",
+                        null=True,
+                    ),
+                ),
                 ("unverified_title", models.TextField()),
                 ("unverified_content_title", models.TextField()),
                 ("unverified_blurb", models.TextField()),
+                (
+                    "auth_provider",
+                    models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to="core.authprovider"),
+                ),
+                ("eligibility_types", models.ManyToManyField(to="core.EligibilityType")),
             ],
         ),
         migrations.CreateModel(
             name="PaymentProcessor",
             fields=[
-                ("id", models.AutoField(primary_key=True, serialize=False, verbose_name="ID")),
+                ("id", models.AutoField(primary_key=True, serialize=False)),
                 ("name", models.TextField()),
                 ("api_base_url", models.TextField()),
                 ("api_access_token_endpoint", models.TextField()),
@@ -81,20 +93,23 @@ class Migration(migrations.Migration):
                 ("card_tokenize_url", models.TextField()),
                 ("card_tokenize_func", models.TextField()),
                 ("card_tokenize_env", models.TextField()),
-                # fmt: off
-                ("client_cert", models.ForeignKey(help_text="The certificate used for client certificate authentication to the API.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
-                ("client_cert_private_key", models.ForeignKey(help_text="The private key used to sign the certificate.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
-                ("client_cert_root_ca", models.ForeignKey(help_text="The root CA bundle used to verify the server.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
                 ("customer_endpoint", models.TextField()),
-                # fmt: on
                 ("customers_endpoint", models.TextField()),
                 ("group_endpoint", models.TextField()),
             ],
         ),
+        migrations.CreateModel(
+            name="PemData",
+            fields=[
+                ("id", models.AutoField(primary_key=True, serialize=False)),
+                ("text", models.TextField(help_text="The data in utf-8 encoded PEM text format.")),
+                ("label", models.TextField(help_text="Human description of the PEM data.")),
+            ],
+        ),
         migrations.CreateModel(
             name="TransitAgency",
             fields=[
-                ("id", models.AutoField(primary_key=True, serialize=False, verbose_name="ID")),
+                ("id", models.AutoField(primary_key=True, serialize=False)),
                 ("slug", models.TextField()),
                 ("short_name", models.TextField()),
                 ("long_name", models.TextField()),
@@ -103,13 +118,62 @@ class Migration(migrations.Migration):
                 ("info_url", models.URLField()),
                 ("phone", models.TextField()),
                 ("active", models.BooleanField(default=False)),
-                # fmt: off
-                ("private_key", models.ForeignKey(help_text="The Agency's private key, used to sign tokens created on behalf of this Agency.", on_delete=models.deletion.PROTECT, related_name="+", to="core.PemData")),  # noqa: E501
                 ("jws_signing_alg", models.TextField(help_text="The JWS-compatible signing algorithm.")),
-                ("payment_processor", models.ForeignKey(on_delete=models.deletion.PROTECT, to="core.paymentprocessor")),
                 ("eligibility_types", models.ManyToManyField(to="core.EligibilityType")),
-                ("eligibility_verifiers", models.ManyToManyField(to="core.eligibilityverifier")),
-                # fmt: on
+                ("eligibility_verifiers", models.ManyToManyField(to="core.EligibilityVerifier")),
+                (
+                    "payment_processor",
+                    models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to="core.paymentprocessor"),
+                ),
+                (
+                    "private_key",
+                    models.ForeignKey(
+                        help_text="The Agency's private key, used to sign tokens created on behalf of this Agency.",
+                        on_delete=django.db.models.deletion.PROTECT,
+                        related_name="+",
+                        to="core.pemdata",
+                    ),
+                ),
             ],
         ),
+        migrations.AddField(
+            model_name="paymentprocessor",
+            name="client_cert",
+            field=models.ForeignKey(
+                help_text="The certificate used for client certificate authentication to the API.",
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="core.pemdata",
+            ),
+        ),
+        migrations.AddField(
+            model_name="paymentprocessor",
+            name="client_cert_private_key",
+            field=models.ForeignKey(
+                help_text="The private key, used to sign the certificate.",
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="core.pemdata",
+            ),
+        ),
+        migrations.AddField(
+            model_name="paymentprocessor",
+            name="client_cert_root_ca",
+            field=models.ForeignKey(
+                help_text="The root CA bundle, used to verify the server.",
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="core.pemdata",
+            ),
+        ),
+        migrations.AddField(
+            model_name="eligibilityverifier",
+            name="public_key",
+            field=models.ForeignKey(
+                help_text="The Verifier's public key, used to encrypt requests targeted at this Verifier and to verify signed responses from this verifier.",  # noqa
+                on_delete=django.db.models.deletion.PROTECT,
+                related_name="+",
+                to="core.pemdata",
+            ),
+        ),
     ]
diff --git a/benefits/core/models.py b/benefits/core/models.py
--- a/benefits/core/models.py
+++ b/benefits/core/models.py
@@ -68,6 +68,8 @@ class EligibilityVerifier(models.Model):
     jwe_encryption_alg = models.TextField(help_text="The JWE-compatible encryption algorithm")
     jws_signing_alg = models.TextField(help_text="The JWS-compatible signing algorithm")
     auth_provider = models.ForeignKey(AuthProvider, on_delete=models.PROTECT, null=True)
+    auth_scope = models.TextField(null=True)
+    auth_claim = models.TextField(null=True)
     selection_label = models.TextField()
     selection_label_description = models.TextField(null=True)
     start_content_title = models.TextField()


Test patch: