Phase 2 releasemay bring breaking changes. The documentation page is being updated to reflect new implementations.

Identification

Identification scopes simplify the onboarding process for users by providing apps with compact endpoints. pasby™ identification flows are most importantly used for:

  • Authentication
  • KYC
  • Registration

On this note the identification scopes support 3 flow action types:

  • login
  • signup
  • link

Each flow action acts differently when interfaced with by pasby™-users.

The identification model

An identification flow model will contain information about the flow reference ID, its date of creation and expected expiration, the IP address of where this flow originated, your apps information, a list of the ID data claims you've requested from your target user and a signature response from pasby™ servers.

The signature is used by pasby™ to process the flows origin and validity.

Properties

  • Name
    id
    Type
    string
    Description

    Unique identifier for this flow.

  • Name
    consumer
    Type
    string
    Description

    The ID of the flow creating apps organisation.

  • Name
    app
    Type
    string
    Description

    The ID of the flow creating app.

  • Name
    name
    Type
    string
    Description

    The alphabetic name of the flow creating app.

  • Name
    user
    Type
    string
    Description

    pasby™ user.

  • Name
    mode
    Type
    string
    Description

    e-ID mode of flow; would always be identification in this case.

  • Name
    iat
    Type
    number
    Description

    Timestamp of request creation in unix format.

  • Name
    exp
    Type
    number
    Description

    Timestamp of request expiration in unix format.

  • Name
    acquireClaims
    Type
    array
    Description

    An array of requested ID data claims.

  • Name
    signature
    Type
    string
    Description

    jwt signature stamp from pasby™-server.

  • Name
    ip
    Type
    string
    Description

    IP address of where flow originated from.

  • Name
    useragent
    Type
    string
    Description

    Identifies the application or operating system which propagated the flow request.

  • Name
    payload
    Type
    string
    Description

    The description of the flow intent.


POST/{{version}}/identification/same-device

Same device

The identification:same scope in pasby™ is otherwise called Autostart flow. As at the time of writing this, pasbys are distributed mobile first. This means every pasby user has a pasby mobile app, on their tablet or smartphone to manage their identity.

Same-device flows are when the user visits a service provider's application (web/mobile) on the same device as their pasby is installed.

Identification flows that begin this way are automatically picked up and handled by the pasby app once a pasby button variant is clicked/pressed/engaged.

Request Body

KeyTypeDescription
action(text)Flow action to be performed
claims(array)Array of ID data claims
payload(sting)Describe the action intent to your user

Request

POST
/v1/identification/same-device
cURL "https://s.pasby.africa/api/v1/identification/same-device" \
-H "x-access-secret: snb_" \
-H "x-api-key: bk-test_" \
-d "{"action": "signup", "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

Request

POST
/v2/identification/same-device
cURL "https://s.pasby.africa/api/v2/identification/same-device" \
-H "x-api-key: bk-test_" \
-H "x-access-secret: snb_" \
-d "{"action": "signup", "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

See pasby™ demo sample code server to better understand how to use autostart flows with the SDKs.

Response

201 Created
{
    "status": "successful",
    "reason": "Identification request created",
    "data": {
        "link": "https://open.pasby.africa/app/?mode=identification&id=req_1714661447-NUkY&source=mobile",
        "request": {
            "id": "req_",
            "consumer": "bcn_•••••••",
            "app": "app_•••••••",
            "mode": "identification",
            "action": "signup",
            "user": "",
            "acquireClaims": [
                "naming.family",
                // ...
            ],
            "signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InJlcV8xNzE0NjYxNDQ3LU5Va1kiLCJtb2RlIjoiaWRlbnRpZmljYXRpb24iLCJhY3Rpb24iOiJzaWdudXAiLCJuYW1lIjoiQml2cmEiLCJjb25zdW1lciI6ImJjbl9jMjQzMWU2Ni1hN2Q3LTQwNmYtOGMyOC03MTVjOWRjNzI4ZTMiLCJwYXlsb2FkIjoiQSBzaW1wbGUgcGF5bG9hZCB1c2VkIGR1cmluZyBwYXNieeKEoiBzYW1lLWRldmljZSBhdXRoZW50aWNhdGlvbiBmbG93IiwiYXBwIjoiYXBwXzAzYzY5YzUwLTdhNGEtNWJhYS1iYTgyLWFhODEwODRhMTQ5ZSIsInVzZXJhZ2VudCI6IlBvc3RtYW5SdW50aW1lLzcuMzguMCIsInVzZXIiOiIiLCJpcCI6Ijo6MSIsImlhdCI6MTcxNDY2MTQ0NywiZXhwIjoxNzE0NjYxODA3LCJhY3F1aXJlQ2xhaW1zIjpbIm5hbWluZy5mYW1pbHkiLCJuYW1pbmcuZ2l2ZW4iLCJuYW1pbmcubWlkZGxlIiwiYmlvLmJpcnRobnVtYmVyIiwiYmlvLmJpcnRoZGF0ZSIsImJpby5nZW5kZXIiLCJuYXRpb25hbGl0eS5yZXNpZGVuY2UiLCJuYXRpb25hbGl0eS5wcmltYXJ5IiwiY29udGFjdC5lbWFpbCJdfQ.u6ygRZwrOw-Aet2AvfTBaiBpdJByTeDLAK8sFtU2TGU",
            // ....
        }
    },
    // ...
}

Response body

ObjectDescription
requestStandard Identification flow data model
linkOn the client end you call upon this string/url to begin identification flow.

identification:same returns a link object on a successful response. This link object should be opened on the client-end once received. If the user has an active pasby on his/her device the pasby™-app will automatically handle this identification flow. Otherwise the user will be shown a how to guide about how to get and activate a pasby for their national identity.

This scope only attributes a user to your identification flow if their pasby™ was the first to pick up the flow request when it was created. You are not allowed to direct an identification request to anyone's NIN using this scope.


POST/{version}/identification/wildcard

Wildcard

The identification:wildcard scope in pasby™ is otherwise called Secure start. This eliminates the need for users to write their NINs or any other identifier when trying to interact with your platform.

Secure starts: Use a QR code mechanism to begin an identification flow. The QR code data is returned as seeds objects in the JSON response from pasby™. You must then present these seeds randomly as a QR code for your user audience to scan.

identification:wildcard is ideal when the user visits a service provider on one device and uses the pasby™-app on another device. Once the user scans any of the displayed QR codes created by your client with their pasby™-app, a session is created for just that user and your app. It's a first-pick, first-serve mechanism, meaning any other scans will be automatically void.

Request Body

KeyTypeDescription
action(text)Flow action to be performed
claims(array)Array of ID data claims
seeds(number)Number of unique flow codes to generate for QR code generation purpose
payload(sting)Describe the action intent to your user

Request

POST
/v1/identification/wildcard
cURL "https://s.pasby.africa/api/v1/identification/wildcard" \
-H "x-access-secret: snb_" \
-H "x-api-key: bk-test_"
-d "{"action": "login", "seeds": 4, "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

Request

POST
/v2/identification/wildcard
cURL "https://s.pasby.africa/api/v2/identification/wildcard" \
-H "x-api-key: bk-test_" \
-H "x-access-secret: snb_" \
-d "{"action": "login", "seeds": 4, "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

See pasby™ demo sample code server to better understand how to use securestart flows with the SDKs.

Response

201 Created
{
    "status": "successful",
    "reason": "Identification request created",
    "data": {
        "request": {
            "id": "req_",
            "consumer": "bcn_•••••••",
            "app": "app_•••••••",
            "mode": "identification",
            "action": "login",
            "user": "",
            "acquireClaims": [
                "naming.family",
                // ...
            ],
            "signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InJlcV8xNzE0NjYxNDQ3LU5Va1kiLCJtb2RlIjoiaWRlbnRpZmljYXRpb24iLCJhY3Rpb24iOiJzaWdudXAiLCJuYW1lIjoiQml2cmEiLCJjb25zdW1lciI6ImJjbl9jMjQzMWU2Ni1hN2Q3LTQwNmYtOGMyOC03MTVjOWRjNzI4ZTMiLCJwYXlsb2FkIjoiQSBzaW1wbGUgcGF5bG9hZCB1c2VkIGR1cmluZyBwYXNieeKEoiBzYW1lLWRldmljZSBhdXRoZW50aWNhdGlvbiBmbG93IiwiYXBwIjoiYXBwXzAzYzY5YzUwLTdhNGEtNWJhYS1iYTgyLWFhODEwODRhMTQ5ZSIsInVzZXJhZ2VudCI6IlBvc3RtYW5SdW50aW1lLzcuMzguMCIsInVzZXIiOiIiLCJpcCI6Ijo6MSIsImlhdCI6MTcxNDY2MTQ0NywiZXhwIjoxNzE0NjYxODA3LCJhY3F1aXJlQ2xhaW1zIjpbIm5hbWluZy5mYW1pbHkiLCJuYW1pbmcuZ2l2ZW4iLCJuYW1pbmcubWlkZGxlIiwiYmlvLmJpcnRobnVtYmVyIiwiYmlvLmJpcnRoZGF0ZSIsImJpby5nZW5kZXIiLCJuYXRpb25hbGl0eS5yZXNpZGVuY2UiLCJuYXRpb25hbGl0eS5wcmltYXJ5IiwiY29udGFjdC5lbWFpbCJdfQ.u6ygRZwrOw-Aet2AvfTBaiBpdJByTeDLAK8sFtU2TGU",
            // ....
        },
        "seeds": [
            "pasby://edbee6303ddcd8d89b6f3052385954b4eb82e7-vi(eb4ae73b5f431deffaeb047cf028e8bc)",
            // ...
        ]
    },
    // ...
}

Response body

ObjectDescription
requestStandard Identification flow data model
seedsOn the client end you create an animated QR code for scanning by randomly shuffling the unique flow codes found in this array.

identification:wildcard returns a seed array object on a successful response. Use the string contents of this array to generate on your client-end a QR code for your user audience to scan. The user will have to open the pasby app and then scan the QR code to process your flow request.

This scope only attributes a user to your identification flow if their pasby™ was the first to pick up the flow request as it was created. You are not allowed to direct an identification request to anyone's NIN using this scope.


POST/{version}/identification/different-device

Different device

The ---:another scopes in pasby™ are a unique type of flow requests which adopts Direct starts. This scope type require a NIN (National Identification Number) to operate.

Direct start: Uses a user's NIN entry to begin an identification flow. identification:another will immediately propagate a flow request to the pasby™-user's devices to process his/her consent to your identification flow.

Request Body

KeyTypeDescription
user(text)The unique NIN identifier of an African national.
action(text)Flow action to be performed
claims(array)Array of ID data claims
payload(sting)Describe the action intent to your user

Request

POST
/v1/identification/different-device
cURL "https://s.pasby.africa/api/v1/identification/different-device" \
-H "x-access-token: {bearer-token}" \
-H "x-api-key: bk-test_" \
-d "{"action": "login", "user": "12345678910", "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

Request

POST
/v2/identification/different-device
cURL "https://s.pasby.africa/api/v2/identification/different-device" \
-H "x-api-key: bk-test_" \
-H "x-access-secret: snb_" \
-d "{"action": "login", "user": "12345678910", "claims": ["naming.family","naming.given","contact.email"], "payload": "A description of this flow action intent"}"

See pasby™ demo sample code server to better understand how to use direct starts flows with the SDKs.

Response

201 Created
{
    "status": "successful",
    "reason": "Identification request created",
    "data": {
        "request": {
            "id": "req_",
            "consumer": "bcn_•••••••",
            "app": "app_•••••••",
            "mode": "identification",
            "action": "login",
            "user": "12345678910",
            "acquireClaims": [
                "naming.family",
                // ...
            ],
            "signature": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6InJlcV8xNzE0NjYxNDQ3LU5Va1kiLCJtb2RlIjoiaWRlbnRpZmljYXRpb24iLCJhY3Rpb24iOiJzaWdudXAiLCJuYW1lIjoiQml2cmEiLCJjb25zdW1lciI6ImJjbl9jMjQzMWU2Ni1hN2Q3LTQwNmYtOGMyOC03MTVjOWRjNzI4ZTMiLCJwYXlsb2FkIjoiQSBzaW1wbGUgcGF5bG9hZCB1c2VkIGR1cmluZyBwYXNieeKEoiBzYW1lLWRldmljZSBhdXRoZW50aWNhdGlvbiBmbG93IiwiYXBwIjoiYXBwXzAzYzY5YzUwLTdhNGEtNWJhYS1iYTgyLWFhODEwODRhMTQ5ZSIsInVzZXJhZ2VudCI6IlBvc3RtYW5SdW50aW1lLzcuMzguMCIsInVzZXIiOiIiLCJpcCI6Ijo6MSIsImlhdCI6MTcxNDY2MTQ0NywiZXhwIjoxNzE0NjYxODA3LCJhY3F1aXJlQ2xhaW1zIjpbIm5hbWluZy5mYW1pbHkiLCJuYW1pbmcuZ2l2ZW4iLCJuYW1pbmcubWlkZGxlIiwiYmlvLmJpcnRobnVtYmVyIiwiYmlvLmJpcnRoZGF0ZSIsImJpby5nZW5kZXIiLCJuYXRpb25hbGl0eS5yZXNpZGVuY2UiLCJuYXRpb25hbGl0eS5wcmltYXJ5IiwiY29udGFjdC5lbWFpbCJdfQ.u6ygRZwrOw-Aet2AvfTBaiBpdJByTeDLAK8sFtU2TGU",
            // ....
        }
    },
    // ...
}

Response body

ObjectDescription
requestStandard Identification flow data model

Identity non-existent on pasby™

In such a situaion where the provided NIN hasn't been linked to pasby™ we return to you the below response.

Response

400 Bad Request
{
    "status": "failed",
    "reason": "National does not have a pasby™ digital ID",
}

Handling Claims

As established in the flows:ping scope description, completed identification flows return an encrypted map object of the user's consented ID data claims.

Before these claims could be used within your app, you'd need to decypher each with your private keys. We wrote a simple typescript function to help you achieve this in real time.

Response

Raw claims
{
  // ...,

  "claims": {
       "contact": {
          "email": "y6l/srG+g/2l2QinsjXxnn4MxY0cTzIDFiRrChjtSIl/LUUkQt8zAUsY4UIPHJDb+LvMH8LHN6LWZ8HNZ+Y3L36Dwy3KdwWSheDrWsXskxVfl5gHGnPl/lvQjyWuxcfwAlH161oJZwKpLhGsVJ8UkI7mm/l+jKznhio+VRsaKcJexky92hE+0rkpsQfWKd25WV53hlXM9n8PQJHzkUOzZwpel3YYo/YPU8hhWaHkFJjY3qnzs9qE+qLQ6RazrwHZz9NtIOYOtajLumQ7QLlrsc3CyCEucPUfNmj/WAWSuikDTegDJmOMElt0Sqf7SsIOGT/Eewd0B+uPxuXtJPR0+ZmHF69IzrtlSSMtVYY5wZt5vjVCrbw9mhVkdkanGKrh3KyjHJE8m6rfNscYUy8768YJvA36FIvzWfk89aknKSaf2L+gLc9BM9zxAtPM5Qcz3K6D8zi2qKdcxZBCoqEvEZYltOsHE8TMRug3HfdEaihVr8VTGwBiNE7ii1D0XRxR36WdEymriy499DkXBri6rRPQxS0rRDr4RqJV0+7rlcmLxYUjvq/ii/ONGiZFtfw0zDtz42PqKyokUQOxZqVAdTc8SvrPoBk/bVpo7gvZUXfYSxG+5e3HqEixQKuCXHSeJH9tCgHilXJV2DaLgqx10TVJcW2NnaOOvIBbUNs2NSQ="
      },
       "naming": {
          "family": "SsF83HO/6g6+Sf+6n0nl3NhSJoEsMYYy5KMuBkIrtH33pD+LanPTUlYcZSYtgOpYV2ozq8kEE7kYalsyh/Kg/JzRCVO35N/KLuwddVZAgkW1AmWpzjEa3yssCTI1HPSG6VFRuV+ITEq1tGnuNzbncRkTbfwdQbGDO4M7oYKg3o7z67Hv4lXWhKc1cDqee95Ja/JRmbsVqSssJbnNUgMxvCyWJQej2ALN1J4lhPsy+WWWX2l6ANsbCsKQMQcQeGQwPfCabiSBazZv2YxRL5CN/gaIpIvjNvBglnJoc2qFPSKzk5VNeJkpXQNvd3HY0O/5ZxzfHR7y/ZUqkyBB9TJc2XsANGtzbrmHnJy7fq6W0ixxJQDeGo3qfsZmoaUb9967RIQ/DRG9To1CbWw1KXDqSbwvaYfOCxR0kXLJKRzV/QNBRzAq8XTe6XgHBGEfkkJR7/dG7Cpt1Jf9tm1PdkRsMYQoNFPhHjAGRbLGsLYcawK1BgqOXM9JMpSZKizGxF6MvfIe4ovC2TS6Y+cWXdUDTFURdSvvY4D+bjAryiCkPYybAFjR1okLINdei0/KyfJXz4qYiZQd4tp+PAd7wi26fABwDeBA8NDFZOYB01P9ACT2pgHGoDIVopf8l2n5cEztKYkIze3PHgvhmGWZP7cz+3paX4kcIr8sg+Q2VVlOm4g=",
          "given": "LqDr6DjnleWbPLESTCd8t9ttuwFL4fwiW1R3hS5Q/o/jk/7K8E1P2Kup2iSuVWwriQ9KLwpzUMhcs7rnDhChUZyJXyh1d2VNzgbTDRNaW2h0/1OHJLnQs6s+hsW5kFrfDyt2KPEHvn1vMVIaEdDSzLmtQC2JQjiFvcVw8oub/CQedXCYWsuui1A8GTef+0EGD78tz46iFEt1hJcijE4CdKTGuH8Ph7nd3rwSpg4APLVcU82ywx4sJkkz3Ym2Vk0Yk2yaDL8WBLqMWHh9jNMvpKgwA9RiocDP6ci8s/Elm2WNE+GspFYur7moEn04NVQvkZbDaKRXKU7FrPvtwX/Me8C2gv4/FnevNas4EOsx8rxhPvmWD20U1o9TCUHzecJg5AJMQ4Y4t90jjaINQ7f7IMIZZJ3RR5M2zs9uq2UdMcW0C2MCjqe9aydWs4WqkFeu2YoWlNoOs3FPVpP2OzAs77MDcnf/dltywz3LZMXrt62ZRCaVIIA1aj/tNewT9NBbrBYnaFzfpaHVOWaWFEyLrmTI1nb0k7pB7o3OAyRYoOCwQhJ6ox5L8PxVaJyjAADZxLkym76E4y6kCEHMe6xaM7L+BBuYhVg4TgOzxH/5b/A3q7ZAKzf9g3Pvm13JZMvsOJr9gUc+bnx7ZsNNrjjeTX4P9riDipU5fR250yT6/N8=",
      },
  }
}

You can simply decrypt the claims by passing the object to a custom function which parses each string against your RSA private key.

  const JSEncrypt = require("node-jsencrypt");

  /**
   * Decrypt the claims received from your flow ping method. The decryption requires the calling apps private key certificate. This private-key can be found in the apps service-file
   * @param {string} enb your apps private key
   * @param {Record<string, unknown>} params argument
   * @return {void}
   */
  function perform(enb:string, claims:Record<string, unknown>) {
      const crypt = new JSEncrypt();
      crypt.setKey(enb);
      var contact = claims['contact'] as Record<string, unknown>;
      var text = crypt.decrypt(contact['email']);

      console.log(`JSE === ${text}`);
  }

A much compact function can be found in our open source demo sample code.

Once decrypted successfully you'll have the ID data claims in alphabetic letterings. Example below:

Decrypted claims

{
  "claims": {
      "contact": {
          "email": "john.doe@example.com"
      },
      "naming": {
          "family": "Doe",
          "given": "John"
      }
  }
}

Was this page helpful?