Quadrata Integration
  • INTRODUCTION
    • Introduction to Quadrata
    • Passport Attributes
  • HOW TO INTEGRATE
    • Quadrata SDK
      • Get Started Quickly
      • Advanced
        • Installation
        • SDK Configuration
        • Onboarding Example
        • Client Libraries
          • Client Configuration
          • Client Lazy Loading
          • Client Eager Loading
          • Client Helper Component
          • Client React Hooks
            • useOnboardStatus
          • Client Examples
            • With Wagmi Connect
            • KYC Only
            • KYB Only
            • All In One
        • API Libraries
          • API Configuration
          • API Service Options
          • API Service Libraries
            • Create Access Token
            • Create Privacy Access Token
            • Fetch Attribute Values
            • Fetch Onboard Status
            • Fetch Passport List
            • Fetch Privacy Data
            • Fetch Privacy Grants
            • Fetch Wallet Screening
            • Revoke Privacy Grants
    • Onboard users
      • Individual Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. API Onboard Status
        • 4. QuadClient Package
        • 5. Privacy Data Permissions
        • 6. Full Example
      • Business Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. QuadrataKyb Package
        • 4. Privacy Data Permissions
        • 5. Full Example
      • All-In-One Passport Onboarding
        • 1. Installation
        • 2. API Authentication
        • 3. QuadrataReact Package
        • 4. Full Example
    • Request Privacy Data
      • List of Privacy Data
      • Privacy Data Permissions
      • API Requests
        • How to sign API
          • Full Example
          • Generate ECDSA Key Pair
        • API Get Privacy Permissions
        • API Privacy Access Token
        • API Get Privacy Data
        • API Revoke Permissions
    • Query attributes
      • Via Smart Contract
        • Query a single attribute
        • Query multiple attributes
        • Query Helper
      • Via API
    • On-Chain Wallet Screening
      • How to sign API
        • Full Example
        • Generate ECDSA Key Pair
      • API Get On-Chain AML Score
    • Webhooks
      • Onboarding Webhooks
      • Ongoing Monitoring Webhooks
      • Webhook Request Signature
    • Burn Passports
  • additional information
    • Smart contracts
    • Quadrata Sandbox
    • Passport Issuers
    • Privileged Roles & Ownership
    • Constants
    • Flex Kit Attributes
      • Smart Contract Addresses
Powered by GitBook
On this page
  • 1. Import Privacy Consent Libs
  • 2. Set the Privacy Permissions requested
  • 3. Handle Privacy Consent Signatures With State
  • 4. Determine If Privacy Permissions Flow Is Needed
  • Privacy Permission Integration Example
  1. HOW TO INTEGRATE
  2. Onboard users
  3. Individual Passport Onboarding

5. Privacy Data Permissions

Configure the onboarding flow to ask for permissions to share privacy data with your dApp.

Previous4. QuadClient PackageNext6. Full Example

Last updated 11 months ago

The privacy permissions flow easily allows users to consent to sharing their with your dApp in a few simple, secure steps.

When a user clicks to "Allow" Privacy Permissions, a request for a signature is presented, which the user must sign with their connected wallet in order to authorize consent for Privacy Data sharing.

In order to use this feature, application owners must have a working implementation of the Quadrata Client. A full example and integration steps can be found here: 6. Full Example

All of our UI libraries support both Javascript and Typescript environments.

Types, interfaces, helper functions, and object maps can be found in and imported from the @quadrata/core-react and @quadrata/client-react NPM packages.

To enable the Privacy Permission flow in your dApp, you need to implement the following steps:

1. Import Privacy Consent Libs

import {
    ...
    PrivacyConsentScopeParamKey,
    PrivacyConsentScopeParams
} from '@quadrata/client-react';

2. Set the Privacy Permissions requested

Set the privacyScopes that will be requested from the user for consent. These need to be passed into QuadClient as a component prop.

const privacyScopes: PrivacyConsentScopeParamKey[] = [
    PrivacyConsentScopeParams.ADR,
    PrivacyConsentScopeParams.DOB,
    PrivacyConsentScopeParams.EM,
    PrivacyConsentScopeParams.FN,
    PrivacyConsentScopeParams.LN
];

Adding this property to your component will enable the Privacy Permission flow and will prompt the onboarding individual for consent to share their Privacy Data.

3. Handle Privacy Consent Signatures With State

Add the state related code to your dApp to manage the privacy consent signature along with the normal onboarding signature.

const [signature, setSignature] = useState<string>();
const [signatureConsent, setSignatureConsent] = useState<string>();

Update the handleSign method to manage the user consent signature that will be available once the user signs, granting access to their Privacy Data.

A boolean flag is passed as the second attribute to the QuadClient onSign event handler. This boolean represents whether or not the signature is for privacy consent or not.

When your dApp receives the consent signature, it needs to be passed back in as a component prop to QuadClient. To do this, update the state so the component re-renders.

This works the same way for onboarding signatures to ensure wallet ownership

const handleSign = async (message: string, isConsent: boolean) => {
    // User clicked the sign button
    // Signing the message and updating state.
    // Will automatically navigate to the next step upon signature update
    if (account) {
        const signature = await signMessageAsync({ message });
        if (isConsent) {
            setSignatureConsent(signature);
        } else {
            setSignature(signature);
        }
    }
};

4. Determine If Privacy Permissions Flow Is Needed

If a user has already allowed access to the Privacy Data that you are requesting, you may not want to put them into the onboarding flow a second time (unless there are unclaimed attributes).

// Quadrata Client
import {
    QuadAttribute,
    PrivacyConsentScopeParamKey,
    PrivacyConsentScopeParams
} from '@quadrata/client-react';

interface AttributeOnboardStatusDto {
    data: {
        type: 'attributes';
        onboardStatus:{
            [attributeName: string]: {
                status: string;
                onboardedAt?: number;
                mintedOnchain?: boolean;
            };
        };
        offeringStatus?: {
            [attributeName: string]: {
                status: string;
                verifiedAt?: number;
            };
        };
        privacyStatus?: {
            [privacyPermission: string]: {
                status: string;
                allowedAt?: number;
                revokedAt?: number;
                revokedReason?: string;
            };
        };
    };
}

function getAttributesToClaim(onboardStatus: any, isBypassMint: boolean) {
    const attributesToClaim = [];
    for (const attributeName in onboardStatus) {
        const { status, mintedOnchain } = onboardStatus[attributeName];
        if (
            (status !== AttributeStatus.READY && status !== 'NOT_APPLICABLE') ||
            (!isBypassMint && !mintedOnchain && status === AttributeStatus.READY)
        ) {
            attributesToClaim.push(attributeName as QuadAttribute);
        }
    }
    return attributesToClaim;
}

function checkConsentNeeded(privacyStatus: any) {
    if (privacyStatus) {
        for (const privacyScopeKey in privacyStatus) {
            const { status } = privacyStatus[privacyScopeKey];
            if (status !== 'ALLOWED') {
                // if any permission is not allowed, all of the desired 
                // permissions need to be requested again
                return true;
            }
        }
    }
    return false;
}

function parseOnboardStatusResponse(
    resp: AttributeOnboardStatusDto,
    isBypassMint: boolean = false
) {
    const { data: { onboardStatus, privacyStatus, offeringStatus } } = resp;

    const attributesToClaim = getAttributesToClaim(onboardStatus, isBypassMint);
    const isConsentNeeded = checkConsentNeeded(privacyStatus);

    if (offeringStatus) {
        // merge attribute to attest from offeringStatus into attributesToClaim
        const attributesToAttest = getAttributesToClaim(offeringStatus, true);
        for (const name of attributesToAttest) {
            if (!attributesToClaim.includes(name)) {
                attributesToClaim.push(name);
            }
        }
    }

    return { attributesToClaim, isConsentNeeded };
}

// Check which attributes to claim for a given wallet
const apiAttributesOnboardStatus = async () => {
    const { NEXT_PUBLIC_QUADRATA_API_URL } = process.env;
    const attributes = requiredAttributes
        .map((attr) => attr.toLowerCase())
        .join(',');
    const privacyScopes = requiredPrivacyScopes.join(',');
    const url = `${NEXT_PUBLIC_QUADRATA_API_URL}/api/v2/attributes/onboard_status?wallet=${account}&chainId=${chainId}&attributes=${attributes}&privacyScopes=${privacyScopes}`;
    const headers = {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${accessToken}`,
    };
    const response = await fetch(url, { method: 'GET', headers });
    if (!response.ok) {
        throw new Error('Onboard status failed');
    }
    return (await response.json()) as AttributeOnboardStatusDto;
};

const response = await apiAttributesOnboardStatus();

// isConsentNeeded is a boolean indicating if the consent flow is needed
const { isConsentNeeded } = parseOnboardStatusResponseForClient(resp, isBypassMint);

let privacyScopesToRequest = [];
if (isConsentNeeded) {
    // if isConsentNeeded is true, all required privacy scopes should be passed in
    privacyScopesToRequest = requiredPrivacyScopes;
}

Privacy Permission Integration Example

import {
    ...
    PrivacyConsentScopeParamKey,
    PrivacyConsentScopeParams
} from '@quadrata/client-react';

// QuadClient config
const quadConfig: QuadClientConfig = {
    _debug: true, // Set to 'false' for production environment
    apiUrl: process.env.NEXT_PUBLIC_QUADRATA_API_URL!,
    environment: QuadClientEnvironment.SANDBOX, // set to QuadClientEnvironment.PRODUCTION for production environment
    protocolName: 'NewCo', // Replace with your company name
};

// Privacy permissions being requested for user consent
// Update these to your dApp's requirements
// PrivacyConsentScopeParamKey[] is an array of available params that your dApp 
// is requesting from the user
const privacyScopes: PrivacyConsentScopeParamKey[] = [
    PrivacyConsentScopeParams.ADR,
    PrivacyConsentScopeParams.DOB,
    PrivacyConsentScopeParams.EM,
    PrivacyConsentScopeParams.FN,
    PrivacyConsentScopeParams.LN
];

// Component
export const MyComponent: React.FC<{ accessToken: string }> = ({ accessToken }) => {
    // State
    const [signature, setSignature] = useState<string>();
    const [signatureConsent, setSignatureConsent] = useState<string>();
    
    // Hooks
    // In this example we use rainbowkit and wagmi libraries to manage Web3 
    // connectivity. You might use any other library.
    const { address: account, isDisconnected } = useAccount();
      
    const handleSign = async (message: string, isConsent: boolean) => {
        // User clicked the sign or allow button
        // Signing the message and updating state.
        // Will automatically navigate to the next step upon signature update
        if (account) {
            const signature = await signMessageAsync({ message });
            if (isConsent) {
                // Sets the user consent signature
                setSignatureConsent(signature);
            } else {
                // Sets the user wallet signature for normal Onboarding
                setSignature(signature);
            }
        }
    };
    
    // Requesting user PII
    return (
        <QuadClient
            ...
            accessToken={accessToken}
            account={account}
            config={quadConfig}
            onHide={onHide}
            onSign={handleSign}
            privacyScopes={privacyScopes || undefined}
            signature={siganture}
            signatureConsent={signatureConsent}
        >
            <CustomLoader />
        </QuadClient>
    );
};

You can find a full list of Privacy Permission Parameters that you can add to your privacyScopes on the ""."" page.

To help you make this decision, the endpoint has been modified to accept optional privacyScopes as a query parameter. If provided, the response payload will contain which permissions have already been allowed, and which permissions you need to ask the user for.

See the for a full integration example

Request Privacy Data
List of Privacy Data
API Onboard Status
Full Example
Import Privacy Libs
Set the Privacy Permissions requested
Handle Privacy Consent Signatures With State
Determine If Privacy Permissions Flow Is Needed
privacy data