Introduction

This documentation serves as a guide to integrate with Civic’s Secure Identity Platform (SIP). The platform provides partners with functionality such as

secure 2FA user login

secure private 2FA user login

onboarding of verified users with customized flows

Integration

Civic Hosted Services provides a flow similar to the traditional oAuth2 authorization code flow, with Civic performing the role of the Authorization server. This implementation

minimises server side development required by the partner.

delivers a secure solution.

is the simplest route to integration.

Civic Hosted Services

The general flow is explained using the example of user signup.

1. Signup. The user clicks “Signup with Civic” button on your website page. The eventhandler calls a method in the CivicJS library to initiate signup.

2. Launch Popup. A modal is displayed which contains an iframe to house the QR code. A request is made to the Civic server to generate a QR code for your scope request.

3. QR Code. The server checks that the domain for the parent document of the iframe corresponds to the domain white list set in the partner account before serving the code. The QR code bridges the air gap between the browser and the user’s smart phone.

4. Scan. The user scans the QR code using the Civic mobile app and is prompted to authorize or deny the scope request. The prompt highlights the data that is being requested and the requesting party.

5. Grant Request. Upon granting the request, the data is sent to the Civic server.

6. Verify offline. The Civic SIP server verifies the authenticity and integrity of the attestations received from the user’s mobile app. This process proves that the user data was attested to by Civic and that the user is currently in control of the private keys relevant to the data.

7. Verify on the blockchain. The Civic server then verifies that the attestations are still valid on the blockchain and have not been revoked.

8. Encrypt and cache. The data is encrypted and cached on the Civic server. Once this data is cached, a polling request from the iframe will receive a response containing an authorization code wrapped in a JWT token. The CivicJS browser-side library passes the token to the parent document. Your site is then responsible for passing the JWT token to your server.

9. Authorization Code exchange. Use the Civic SIP sdk on your server to communicate with the Civic SIP server and exchange the authorization code (AC) for the requested user data. The SIP server first validates the JWT token, ensuring it was issued by Civic, is being used by the correct application id, and that the expiry time on the token has not lapsed. The enclosed AC is then verified and the encrypted cached data returned.

10. Decrypt. Your server receives the encrypted data where it is decrypted using your application secret key. The result will contain a userId and any data requested (such as email, mobile number etc).

11. Complete user signup. At this point you can store the necessary data and redirect the user to your app’s logged in experience.

For subsequent logins the userId can be used to associate the user with your accounts system.

This example assumes an existing user account on the Civic mobile app. If the user had no profile on the app (or missing data), they would be taken through data capture and verification, before being prompted to authorize the request.

Getting Started

Follow the steps below to integrate using the Civic Hosted option.

Sign up for a developer account on the Civic Integration Portal and create a test application. From here, you will be able to generate the keys necessary for encryption used in the steps below.

Basic requests necessary for simple account creation and 2FA are available to all partners who have signed up on the integration Portal. Extended KYC Beta access requires Civic approval. Learn more and request access here.

Civic as an MFA Solution

In order for Civic to function as an MFA solution, you must use the userID field returned in the Anonymous or Basic scope request response as your MFA credential. Additional information such as email address or phone number can be requested as needed; however, this data is not necessarily a unique identifier for the Civic user.

If your site already utilizes a login method, such as traditional username and password, you will need to enroll your user with Civic after having logged into their accounts. Simply issue a Basic or Anonymous scope request and associate the returned userID with their account credentials in your system. After associating their userID with their account in your system, you can request an Anonymous or Basic scope request behind that user’s original login method as the MFA method.

Browser

Include

<link rel= "stylesheet" href= "https://hosted-sip.civic.com/css/civic-modal.min.css" > <script src= "https://hosted-sip.civic.com/js/civic.sip.min.js" ></script>

Step 1: Include

Include the civic.sip.js script on your page. This exposes a single global object, civic .

Initialize

// Step 2: Instantiate instance of civic.sip var civicSip = new civic . sip ({ appId : 'ABC123' });

<button id= "signupButton" class= "civic-button-a medium" type= "button" > <span> Log in with Civic </span> </button>

Step 2: Initialize

Create an instance of civic.sip , passing in your application ID. This identifies your site to Civic servers. You can find your application ID in the Application details section of the integration portal. Be sure to replace ABC123 with your application ID. We require the origin in the headers of requests from browsers.

Event Handlers

// Step 3: Start scope request. var button = document . querySelector ( '#signupButton' ); button . addEventListener ( 'click' , function () { civicSip . signup ({ style : 'popup' , scopeRequest : civicSip . ScopeRequests . BASIC_SIGNUP }); }); // Listen for data civicSip . on ( 'auth-code-received' , function ( event ) { /* event: { event: "scoperequest:auth-code-received", response: "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiI2Y2EwNTEzMi0wYTJmLTQwZjItYTg2Yi03NTkwYmRjYzBmZmUiLCJpYXQiOjE0OTQyMjUxMTkuMTk4LCJleHAiOjE0OTQyMjUyOTkuMTk4LCJpc3MiOiJjaXZpYy1zaXAtaG9zdGVkLXNlcnZpY2UiLCJhdWQiOiJodHRwczovL3BoNHg1ODA4MTUuZXhlY3V0ZS1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20vZGV2Iiwic3ViIjoiY2l2aWMtc2lwLWhvc3RlZC1zZXJ2aWNlIiwiZGF0YSI6eyJjb2RlVG9rZW4iOiJjY2E3NTE1Ni0wNTY2LTRhNjUtYWZkMi1iOTQzNjc1NDY5NGIifX0.gUGzPPI2Av43t1kVg35diCm4VF9RUCF5d4hfQhcSLFvKC69RamVDYHxPvofyyoTlwZZaX5QI7ATiEMcJOjXRYQ", type: "code" } */ // encoded JWT Token is sent to the server var jwtToken = event . response ; // Your function to pass JWT token to your server sendAuthCode ( jwtToken ); }); civicSip . on ( 'user-cancelled' , function ( event ) { /* event: { event: "scoperequest:user-cancelled" } */ }); civicSip . on ( 'read' , function ( event ) { /* event: { event: "scoperequest:read" } */ }); // Error events. civicSip . on ( 'civic-sip-error' , function ( error ) { // handle error display if necessary. console . log ( ' Error type = ' + error . type ); console . log ( ' Error message = ' + error . message ); });

Step 3: Event Handlers

Provide a suitable event handler to initiate the Civic scope request. For example, for a signup scenario, place a “Signup with Civic” button on your page (see our style guidelines for the Civic color palette and related iconography). The event handler calls civic.signup , passing in the required scope request.

Provide an event handler to listen for data events. SIP server responses are returned to the browser in the form of a JWT token for security. The JWT token ensures the integrity of the response, the identity of the sender, the intended receipient and valid lifespan of the response. The authorization code will be passed to the handler (wrapped in a JWT token) following authorization by the user. Pass the JWT token to your server to make a server to server call to the SIP server to retrieve the user data.

The auth-code-received event contains the following fields:

Field Required Description event Yes event name type Yes flow type for the response e.g. “code” for authorization code flow response Yes JWT Token in base64 encoded format containing authorization code

Event handlers for user-cancelled and civic-sip-error events can also be provided for custom handling of these event types.

JWT Tokens The decoded JWT token example below shows the format of the tokens used to transfer data:

{ header : { typ : 'JWT' , alg : 'ES256' }, payload : { jti : '45a59d10-6e93-47f6-9185-adacfe28907a' , iat : 1494204971.361 , exp : 1494205151.361 , // 3 minute lifespan iss : 'civic-sip-hosted-service' , aud : '/dev/scopeRequest/authCode' , // valid endpoints for this token sub : 'civic-sip-hosted-service' , data : { codeToken : '81f2564c-e7c0-4869-be49-a88f5738534f' } }, signature : 'xC3CYCFz-p0RWf2CLnnvfb7Fhksu9vSJgHKQIsP4iakp4HI63xoWZZqEiDgcV5S7CULIty_v0fpvJwSs87BgWQ' }

Browser Support

To ensure the best possible results, the Civic browser experience is designed for modern desktop browsers that automatically update. Browsers without reliable automatic update systems are supported as current version -1.

Chrome: latest version

Firefox: latest version

Edge: latest version

Safari (OS X): 10+

Internet Explorer: 11+

Mobile Browser Note

When using the Civic SIP flow from a mobile browser, we do not show the QR Code, but instead direct the user from the browser to the Civic App using deeplinking.

Once the user approves the scope request on the Civic App, they will be redirected back to the browser with a new tab being opened on your integrated web page. We append a query parameter called uuid to the parent URL so that we can identify the fact that this page is loading after returning from the Civic App.

If a uuid query parameter is detected in the parent URL, the Civic library will load the modal up automatically and begin polling for the token response. Once the token is received it will behave as normal and use the code setup in the event listener for auth-code-received .

We suggest testing the mobile browser flow in your integration and ensure any possible special handling in this adapted process.

Using Civic Branding

When creating any visuals relating to Civic, please make use of our brand guideline found here: Civic Brand Guidelines

Server

Use the Civic SIP server sdk relevant to your server side environment to complete the server integration of your signup, login or general scope request flow. Only available for nodeJS (version > 6.10.x) currently. Support will be expanded shortly.

Server Installation: Install the module

npm install civic-sip-api

Initialize

const civicSip = require ( 'civic-sip-api' ); // Step 4: Initialize instance passing your appId and secret. const civicClient = civicSip . newClient ({ appId : 'CO-ABCDEFG1230934545' , prvKey : PRIVATE_KEY , appSecret : APP_SECRET , });

Step 1: Initialize

Create an instance of civic.sip , passing in your application ID, private signing key and secret. Your private keys and secret should only be used on the server and never exposed on the client side. They must be stored securely.

Exchange

// Step 5: Exchange authorization code for user data. civicClient . exchangeCode ( jwtToken ) . then (( userData ) => { // store user data and userId as appropriate console . log ( 'userData = ' , JSON . stringify ( userData , null , 4 )); }). catch (( error ) => { console . log ( error ); });

Step 2: Exchange Authorization Code

Call exchangeCode with the JWT token you received from the browser session to exchange for the requested user data.

The JWT token can only be exchanged once for user data. The user would need to redo the flow if the data needed to be fetched again from Civic.

The Civic sdk creates an authorization header to include in the POST request. This is used to authenticate your request. This header consists of: a string identifier Civic a JWT Token that specifies the endpoint and method being called. It also introduces a time dependency to the request. This is signed using your private key. a HMAC SHA256 message digest of the request body created using your application secret. This ensures the integrity of the request body on the Civic server.

The POST request is then sent to the Civic SIP server.

The Civic SIP server verifies your identity using the signature of the JWT token component of the Authorization header. The continued validity of the header token (expiry) is also verified.

The message digest is then validated to ensure the body of the request has not been tampered with.

The SIP server verifies that the caller is the correct recipient of the token.

User data is then returned to your server encrypted using AES and your secret. The encrypted data is returned as the payload of a JWT Token signed by Civic. The receiver validates this token to ensure it has been sent by Civic.

Upon receiving a response at your server, the Civic sdk decrypts the data using your application secret and returns the user data.

The userId can be associated with your user account system for user identification in future logins.

Exchange Code Errors

When exchanging the token for user data, beyond the standard error codes, these are the ones specific to this request.

Error Code Meaning 403 Forbidden: Duplicate Request – The jwtToken can only be used once for user data exchange. If the token is exchanged and user data needs to be fetched again, a new token needs to be generated and the request approved by the user.

Mobile integration

Civic provides libraries to assist partner apps to integrate the functionality provided by the Secure Identity Portal. These libraries provide an easy way to add a Connect with Civic button to a mobile app. They also provide all of the network communication to start a scope request. The Civic Mobile App will be opened on the device and will give the user the opportunity to authorize the use of their data. Once the user has authorized the scope request, the libraries will fetch and decrypt the data that was requested in the scope request and authorized by the user.

You need to sign up on the Civic Integration Portal to create an app. You will need the appId and the secret provided by the portal in order to whitelist your app. You can create one app that supports both Android and iOS with the same appId.

Android

The Android library can be found in the public repo civic-connect-android-public. This repo provides documentation on how to integrate as well as a sample app. The partner does not need to build the library as the library can be accessed from the jcenter repositories. See the sample app and documentation for instructions.

iOS

The iOS library can be found in the public repo civic-connect-ios-public. This repo provides documentation on how to integrate as well as a sample app. As with the Android implementation, the partner does not need to build the library as a library binary is provided. See the README of the repo for more detail.

Scope Requests

Scope Requests detail specific sets of verified data you wished returned from the user. The two currently available scope requests are detailed below. See Event Handlers for documentation on how to implement these requests.

BASIC_SIGNUP

Basic Sign Up

var button = document . querySelector ( '#signupButton' ); button . addEventListener ( 'click' , function () { civicSip . signup ({ style : 'popup' , scopeRequest : civicSip . ScopeRequests . BASIC_SIGNUP }); });

The BASIC_SIGNUP scope request returns the user’s basic account info - email and phone. It is most commonly used for secure login and signup solutions when no additional identity verification is required.

Label Example Value Description contact.personal.email jonsmith@example.com The user’s verified email. contact.personal.phoneNumber +1 5551234567 The user’s verified phone number. isValid true Civic SIP service checks whether or not the data is still considered valid on the blockchain. isOwner true Civic SIP service challenges the user during scope request approval to ensure the user is in control of the private key originally used in the issuance of the data attestation. userId c6d5795…b42 Anonymous user identifier

Example of data returned for a ScopeRequest of BASIC_SIGNUP

userData = { "data" : [ { "label" : "contact.personal.email" , "value" : "jonsmith@example.com" , "isValid" : true , "isOwner" : true }, { "label" : "contact.personal.phoneNumber" , "value" : "+1 5551234567" , "isValid" : true , "isOwner" : true } ], "userId" : "c6d5795f8a059ez5ad29a33a60f8b402a172c3e0bbe50fd230ae8e0303609b42" }

ANONYMOUS_LOGIN

Anonymous Login

var button = document . querySelector ( '#signupButton' ); button . addEventListener ( 'click' , function () { civicSip . signup ({ style : 'popup' , scopeRequest : civicSip . ScopeRequests . ANONYMOUS_LOGIN }); });

(BETA) The ANONYMOUS_LOGIN scope request returns a unique ID for the user but no other identifying information. Though not shared, users must still have a verified phone number and email address to complete an anonymous login request. The intent of this scope request is to enable the creation of secure and anonymous user accounts that are still backed by a unique Civic ID.

Label Example Value Description isValid true Civic SIP service checks whether or not the data is still considered valid on the blockchain. isOwner true Civic SIP service challenges the user during scope request approval to ensure the user is in control of the private key originally used in the issuance of the data attestation. userId c6d5795…..b42 Anonymous user identifier

Example of data returned for a ScopeRequest of ANONYMOUS_LOGIN

{ "data" : [ { "label" : "verifications.levels.CIVIC:IAL1" , "value" : "CIVIC:IAL1" , "isValid" : true , "isOwner" : true } ], "userId" : "c6d5795f8a059ez5ad29a33a60f8b402a172c3e0bbe50fd230ae8e0303609b42" }

PROOF_OF_IDENTITY

Proof Of Identity

var button = document . querySelector ( '#signupButton' ); button . addEventListener ( 'click' , function () { civicSip . signup ({ style : 'popup' , scopeRequest : civicSip . ScopeRequests . PROOF_OF_IDENTITY }); });

The PROOF_OF_IDENTITY scope request returns the full set of verified information for a user’s identity check. Note that attempting this request without prior approval will return an unauthorized error. Request access here.

Label Example Value Description documents.genericId.type passport Type of ID document provided for KYC verification. documents.genericId.number ABC1112223333 ID string (such as Driver’s License or Passport number) for the document provided. documents.genericId.name John Peter Smith Name given on the ID document documents.genericId.dateOfBirth 1980-01-30 Data of birth given on the ID document in YYYY-MM-DD format. documents.genericId.dateOfIssue 2015-06-15 Issued date of the ID document in YYYY-MM-DD format. documents.genericId.dateOfExpiry 2021-1-01 Expiry date of the ID document in YYYY-MM-DD format. documents.genericId.image /9j/4AA[…] base64 encoded image of the ID document. documents.genericId.image_md5 81ece061fd53c479f1f7a0cdfb5d3cf1 md5 hash of the image. documents.genericId.country USA Issuing country of the ID document. contact.personal.email jonsmith@example.com User’s verified email address. contact.personal.phoneNumber +1 5551234567 User’s verified phone number. verifications.levels.CIVIC:IAL1 CIVIC:IAL1 Verification standard used to check the document. This field should be ignored pending future functionality.

PROOF_OF_IDENTITY Response Objects

Possible values for specific fields.



Note: The documents.genericId.type values listed are not exhaustive. It depends on the user’s document type when they verified on their Civic Mobile App. This table lists the common values.

Label Possible Values documents.genericId.type Passport

Driving License

Visa

ID Card documents.genericId.country Three letter ISO code: ALPHA-3 Standard eg: USA

Example of data returned for a ScopeRequest of PROOF_OF_IDENTITY

userData = { "data" : [ { "label" : "verifications.levels.CIVIC:IAL1" , "value" : "CIVIC:IAL1" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.type" , "value" : "Driving License" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.number" , "value" : "A0000000" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.name" , "value" : "Jane Doe" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.dateOfBirth" , "value" : "YYYY-m-d" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.dateOfIssue" , "value" : "YYYY-m-d" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.dateOfExpiry" , "value" : "2021-1-01" , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.image" , "value" : "/9j/4AA..." , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.image_md5" , "value" : "d0a..." , "isValid" : true , "isOwner" : true }, { "label" : "documents.genericId.country" , "value" : "USA" , "isValid" : true , "isOwner" : true } { "label" : "contact.personal.email" , "value" : "jonsmith@example.com" , "isValid" : true , "isOwner" : true }, { "label" : "contact.personal.phoneNumber" , "value" : "+1 5551234567" , "isValid" : true , "isOwner" : true } ], "userId" : "c6d5795f8a059ez5ad29a33a60f8b402a172c3e0bbe50fd230ae8e0303609b42" }

Environments

Partners have access to our test and live environments via environment specific clientID’s and key pairs. ClientID’s and key pairs can be managed in the partner’s dashboard. It is possible to generate multiple ClientID’s. This allows a partner to assign different clientID’s to different subsystems and applications within the organization. This limits the contagion in the event that a private key is compromised, and only that clientID and key pair need to be regenerated.

Our API is served over HTTPS. To ensure data privacy, unencrypted HTTP is not supported. API requests without authentication will also fail.

The test environment is kept in step with the latest live release and does not support earlier versions of the API. We require the version number in the url to keep consistent with the live url convention.

Errors

Civic uses conventional HTTP response codes to indicate the success or failure of an API request. In general, a response code of 2xx indicates the operation was successful. Other error codes indicate either a client error (4xx) or a server error (5xx).

The Civic API uses the following error codes:

Error Code Meaning 400 Bad Request – Check the response ‘message’ field for details. 401 Unauthorized – Authentication failed. 405 Method Not Allowed – You tried to access an invalid method. 429 Too Many Requests – Your request was throttled by our gateway. 500 Internal Server Error – We had a problem with our server. Try again later. 504 Endpoint Request Timed-out Exception.