Login Configuration Details

This page details the Login Configuration used to integrate Affinidi Login into your application.

To integrate Affinidi Login into your application and offer a passwordless login experience, you need to create a Login Configuration. Below are the relevant fields when managing Login Configuration:

  • name: is the name of your Login Configuration to quickly identify the purpose of the config you are creating e.g Insurance Website Dev.

  • redirectUris: is the URL on your application where the user gets redirected after the successful authentication.

  • auth: Refers to the client credentials generated post-Login Configuration creation. These details are employed to adjust your OIDC settings and embed Affinidi Login in your application.

    • auth.clientId: Identifies the client within Affinidi Login.

    • auth.clientSecret: In tandem with clientId, it validates the integration with Affinidi Login.

    • auth.issuer: A URL identifier, this accepts and manages the authentication request via Affinidi Login. Furthermore, this URL facilitates OpenID information discovery, presented by Affinidi Login.

  • presentationDefinition (optional): Specifies the data you request from the user to verify their identity. By default, Affinidi Login requests an Email VC, issued by Affinidi upon user registration. This is stipulated in the default presentationDefinition during Login Configuration creation.

  • idTokenMapping (optional): Defines the method of extracting data from the VP Token supplied by the Affinidi Vault and transforming it into an idToken. Affinidi Login then sends this back to the website or the IdP Solution. This process is set out in the default idTokenMapping when crafting a Login Configuration.

  • clientMetadata: (optional) Determines the specifics shown on the consent page as users authenticate with your website.

    • clientMetadata.name: This name appears on the consent page, signifying to the user who is asking for their data.

    • clientMetadata.origin: The domain displayed on the consent page, clarifying to the user the source of the request.

    • clientMetadata.logo: A logo presented on the consent page, symbolising the entity requesting the user’s information.

  • tokenEndpointAuthMethod: Indicates the preferred authentication technique when connecting to Affinidi Login. Set the value to none if you want to implement PKCE flow on Affinidi Login.

  • failOnMappingConflict: A boolean flag indicates whether to interrupt and fail the Login flow if the ID Token Mapping definition contains duplicate field mapping. The default value is True.

  • ari: Refers to a resource identifier of the Login Configuration created under a Project. Use this value to define a policy to grant access to other users for this particular record. Use this guide to learn how to configure policy to grant access to other users on your projects.

You can manage your Login Configurations using Affinidi CLI or  Affinidi Portal.

Presentation Definition and ID Token Mapping

When creating a Login Configuration, it’s not necessary to define a custom presentationDefinition or idTokenMapping. By default, the Login Configuration utilises a presentationDefinition alongside idTokenMapping that requests the Email VC issued to every Affinidi Vault user upon registration.

Here are the default definitions and their evaluation during the Login Flow:

Default Presentation Definition

Within the standard presentation definition of the Login Configuration, we request users to share their Email VC, which is issued by Affinidi. In addition to requesting the Email VC from Affinidi, we also verify the following conditions:

  • The Verifiable Credentials (VC) must be of the Email type.
  • The email address must adhere to the following JSON structure within the VC: $.credentialSubject.email.

From this presentation definition, the Affinidi Vault produces the Verifiable Presentation (VP) sent to Affinidi Login.


{
  "id": "vp_token_with_email_vc",
  "input_descriptors": [
    {
      "id": "email_vc",
      "name": "Email VC",
      "purpose": "Check if data contains necessary fields",
      "constraints": {
        "fields": [
          {
            "path": [
              "$.type"
            ],
            "purpose": "Check if VC type is correct",
            "filter": {
              "type": "array",
              "contains": {
                "type": "string",
                "pattern": "Email"
              }
            }
          },
          {
            "path": [
              "$.credentialSubject.email"
            ],
            "purpose": "Check if VC contains email field",
            "filter": {
              "type": "string"
            }
          },
          {
            "path": [
              "$.issuer"
            ],
            "purpose": "Check if VC Issuer is Trusted",
            "filter": {
              "type": "string",
              "pattern": "^did:key:zQ3shtMGCU89kb2RMknNZcYGUcHW8P6Cq3CoQyvoDs7Qqh33N"
            }
          }
        ]
      }
    }
  ]
}

Default ID Token Mapping

In the default ID token mapping of the Login Configuration, we are mapping on where and how to extract the information from the Verifiable Presentation (VP) sent by Affinidi Vault to generate the idToken that is sent back to the website.

[
  {
    "sourceField": "$.type",
    "idTokenClaim": "$.custom[0].type",
    "inputDescriptorId": "email_vc"
  },
  {
    "sourceField": "$.credentialSubject.email",
    "idTokenClaim": "$.custom[1].email",
    "inputDescriptorId": "email_vc"
  }
]

Use this guide to learn how to modify the presentation definition to include additional data depending on your requirements that must be satisfied by the user from their Vault.

Create Login Configuration

To create a Login Configuration, you can either use Affinidi CLI or  Affinidi Portal.

Using Affinidi CLI

  1. Log in to Affinidi CLI by running:
affinidi start
  1. Once you have successfully logged in, create the Login Configuration by running:
affinidi login create-config \
--name='<Name>' \
--redirect-uris='<Redirect URIs>'
  • --name is what you want your login configuration to be called.
  • --redirect-uris is the URL on your application where the user gets redirected after the successful authentication.

Sample response:

{
  "ari": "ari:identity:ap-southeast-1:687b8872-a618-dt63-8978-e72ac32daeb1:login_configuration/c4f74d936cd31bde1c1fd3c1050bb76s",
  "projectId": "687b8872-a618-4e52-8978-e72ac32daec2",
  "configurationId": "c4f74d936cd31bde1c1fd3c1050bb62d",
  "name": "...",
  "auth": {
    "clientId": "<AUTH.CLIENT_ID>",
    "clientSecret": "<AUTH.CLIENT_SECRET>",
    "issuer": "https://<PROJECT_ID>.apse1.login.affinidi.io"
  },
  "redirectUris": [
    "..."
  ],
  "clientMetadata": {
    "name": "Login Config Name",
    "logo": "https://login.affinidi.com/default-client-logo.svg",
    "origin": "https://example.com"
  },
  "creationDate": "2023-08-11T06:26:37Z",
  "tokenEndpointAuthMethod": "client_secret_post"
}

Learn more on how to manage your Login Configurations using Affinidi CLI.

Using Affinidi Portal

Create new Login Configuratioin
  1. Go to  Affinidi Login under the Services section.

  2. Click on the Create Login Configuration and provide the required details.

  • Name is the string that describes your login configuration.
  • Redirect URIs is the URL on your application where the user gets redirected after the successful authentication.
  1. Click on create and confirm if all the details are correct.
Login Configuratation new client
  1. After confirming the details, another popup shows the Client ID and Client Secret for your Login Configuration. Copy the generated Client Credentials and use them to integrate with Affinidi Login.

  2. After copying the Client ID and Client Secret and closing the popup, you are redirected back to the Affinidi Login page.

Login Configuration uses the default Presentation Definition (presentationDefinition) and ID Token Mapping (idTokenMapping) that is used to request the user’s email address during the authentication flow.

Once you have successfully created a Login Configuration, you can copy the contents of the auth field and configure it on your OIDC settings.

Update Login Configuration

Sometimes, you may want to request fields from the user’s profile stored on their Vault during authentication. To do this, we must update the Login Configuration and modify the default Presentation Definition and ID Token Mapping.

  1. Extract the existing Presentation Definition and ID Token Mapping from the Login Configuration.
affinidi login get-config --id <LOGIN_CONFIG_ID>

The above command will return the Login Configuration record in a JSON format that we can use as a template to update the Presentation Definition and ID Token Mapping.

{
  .....
  "presentationDefinition": {
    "id": "vp_token_with_email_vc",
    "input_descriptors": [
      {
        "id": "email_vc",
        "name": "Email VC",
        "purpose": "Check if data contains necessary fields",
        "constraints": {
          "fields": [
            {
              "path": [
                "$.type"
              ],
              "purpose": "Check if VC type is correct",
              "filter": {
                "type": "array",
                "contains": {
                  "type": "string",
                  "pattern": "Email"
                }
              }
            },
            {
              "path": [
                "$.credentialSubject.email"
              ],
              "purpose": "Check if VC contains email field",
              "filter": {
                "type": "string"
              }
            },
            {
              "path": [
                "$.issuer"
              ],
              "purpose": "Check if VC Issuer is Trusted",
              "filter": {
                "type": "string",
                "pattern": "^did:key:zQ3shtMGCU89kb2RMknNZcYGUcHW8P6Cq3CoQyvoDs7Qqh33N"
              }
            }
          ]
        }
      }
    ]
  },
  "idTokenMapping": [
    {
      "sourceField": "$.type",
      "idTokenClaim": "$.custom[0].type",
      "inputDescriptorId": "email_vc"
    },
    {
      "sourceField": "$.credentialSubject.email",
      "idTokenClaim": "$.custom[1].email",
      "inputDescriptorId": "email_vc"
    }
  ],
  .....
}
  1. Copy the values from presentationDefinition and idTokenMapping and save it in a JSON file. We will use the JSON file to update the config later.
{
    "presentationDefinition": {
        "id": "vp_token_with_email_vc",
        "input_descriptors": [
          {
            "id": "email_vc",
            "name": "Email VC",
            "purpose": "Check if data contains necessary fields",
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.type"
                  ],
                  "purpose": "Check if VC type is correct",
                  "filter": {
                    "type": "array",
                    "contains": {
                      "type": "string",
                      "pattern": "Email"
                    }
                  }
                },
                {
                  "path": [
                    "$.credentialSubject.email"
                  ],
                  "purpose": "Check if VC contains email field",
                  "filter": {
                    "type": "string"
                  }
                },
                {
                  "path": [
                    "$.issuer"
                  ],
                  "purpose": "Check if VC Issuer is Trusted",
                  "filter": {
                    "type": "string",
                    "pattern": "^did:key:zQ3shtMGCU89kb2RMknNZcYGUcHW8P6Cq3CoQyvoDs7Qqh33N"
                  }
                }
              ]
            }
          }
        ]
    },
    "idTokenMapping": [
        {
          "sourceField": "$.type",
          "idTokenClaim": "$.custom[0].type",
          "inputDescriptorId": "email_vc"
        },
        {
          "sourceField": "$.credentialSubject.email",
          "idTokenClaim": "$.custom[1].email",
          "inputDescriptorId": "email_vc"
        }
    ]
}

Update the Presentation Definition

  1. Update the Presentation Definition to include a field from the user profile. See the example below:
{
    "presentationDefinition": {
        "id": "vp_combined_email_user_profile_combined",
        "submission_requirements": [
        {
            "rule": "pick",
            "min": 1,
            "from": "A"
        }
        ],
        "input_descriptors": [
          {
            "id": "email_vc",
            "name": "Email VC",
            "purpose": "Check if data contains necessary fields",
            "group": ["A"],
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.type"
                  ],
                  "purpose": "Check if VC type is correct",
                  "filter": {
                    "type": "array",
                    "contains": {
                      "type": "string",
                      "pattern": "Email"
                    }
                  }
                },
                {
                  "path": [
                    "$.credentialSubject.email"
                  ],
                  "purpose": "Check if VC contains email field",
                  "filter": {
                    "type": "string"
                  }
                },
                {
                  "path": [
                    "$.issuer"
                  ],
                  "purpose": "Check if VC Issuer is Trusted",
                  "filter": {
                    "type": "string",
                    "pattern": "^did:key:zQ3shtMGCU89kb2RMknNZcYGUcHW8P6Cq3CoQyvoDs7Qqh33N"
                  }
                }
              ]
            }
          },
          {
            "id": "profile_vc",
            "name": "Profile VC",
            "purpose": "Check if data contains necessary fields",
            "group": ["A"],
            "constraints": {
              "fields": [
                {
                  "path": [
                    "$.type"
                  ],
                  "purpose": "Check if VC type is correct",
                  "filter": {
                    "type": "array",
                    "pattern": "UserProfile"
                  }
                },
                {
                  "path": ["$.credentialSubject.address.country"]
                }
              ]
            }
          }
        ]
    }
}

In the definition above, we request the user profile country address field from the Vault.

Update the ID Token Mapping

  1. Update the ID Token Mapping to map the additional fields defined in the Presentation Definition to include in the idToken that we will send to the application after successful authentication.
{
    "idTokenMapping": [
    {
      "sourceField": "$.type",
      "idTokenClaim": "$.custom[0].type",
      "inputDescriptorId": "email_vc"
    },
    {
      "sourceField": "$.credentialSubject.email",
      "idTokenClaim": "$.custom[1].email",
      "inputDescriptorId": "email_vc"
    },
    {
      "sourceField": "$.credentialSubject.address.country",
      "idTokenClaim": "$.custom[2].country",
      "inputDescriptorId": "profile_vc"
    }
    ]
}

In the mapping above, we have added the country field of the user profile into the idToken that we will send to the application.

  1. After updating both Presentation Definition and ID Token Mapping on your JSON file created previously, use this file to update the target Login Configuration to use the new definition and mapping.
affinidi login update-config --id <LOGIN_CONFIG_ID> --file <JSONFILE>.json

Updating Other Fields

When updating other fields like redirectUris, name, and clientMedata, you can use either Affinidi CLI or  Affinidi Portal.

Configuring OIDC Settings

In a usual OIDC-enabled application, it requires the following details to enable the OAuth flow:

  • Client ID: This is the identifier of your application. This is the LoginConfig.clientId property from Login Configuration.

  • Client Secret: This is a piece of sensitive information known by the application and authorisation server. It is used to authenticate the application to the authorisation server. This is the LoginConfig.clientSecret property from Login Configuration.

  • Issuer URL: This is used to fetch and exchange access tokens, as well as fetch identity information. This is the LoginConfig.issuer property from Login Configuration. Some IdP platforms support auto-discovery based on the Issuer URL. In the case the IdP does not support auto-discovery, the typical two endpoints required are:

    • Authorisation URL: The authorisation server’s endpoint to retrieve the authorisation code.

    • Token URL: The authentication server’s endpoint to exchange an authorisation code for an access token.

  • Scope: This is used by the application during authentication to authorise access to a user’s details and will be part of the returned ID Token. When configuring the integration of Affinidi Login, the scopes are usually set into the following values:

    • openid: This indicates that the application will use the OIDC standard to authenticate the user.

    • offline_access: This indicates that the access requests include the refresh token after successful authentication of the user.

To view the well-known configuration of the Affinidi Login, use the Issuer URL from the Login Configuration and append the /.well-known/openid-configuration.

<LoginConfig.IssuerURL>/.well-known/openid-configuration