Transaction Signing

View this page for | |

Once the keys are provisioned, the device is ready to perform a Transaction Signing operation (that is, to approve or decline an operation based on details sent by the HID authentication platform). How the application is notified that a transaction is to be signed depends on its deployment. One option is to get a push notification from the server.

For more information about creating a transaction from the Web App/backend integration, refer to the bcauthorize endpoint.

The mobile application signs a transaction as follows:

  1. Create an instance of the HIDDevice (HIDDeviceFactory.newInstance).
  2. Retrieve the transaction identifier (transactionId) for the transaction that will be processed. This identifier can be retrieved from the:
    • Push notification payload received by the application. This is the tds member of the payload

    • List of pending transactions for a specific container retrieved from the server (HIDContainer.retrieveTransactionIds)

    • Scanning a QR code encoded with a userID-less transaction

  3. Get public information (HIDServerActionInfo) from the transaction identifier (transactionId)(HIDDevice.retrieveActionInfo).

    For a userID-less transaction, anHIDInexplicitContainer (9) error containing the list of possible userIDs is raised if several containers exist for the targeted server. The integrating application will need to select a userID from the HID_ERROR_PARAMETERS list in the NSError userInfo dictionary and call HIDDevice.retrieveActionInfo with the userID parameter.

    There is no communication with the server at this point.

    The returned HIDServerActionInfo instance provides the:

  4. Check if the Session Transport Key is protected by a password and prompt the user as required.
  5. Get transaction details from the server (HIDServerActionInfo.getAction).
  6. Get the transaction details (HIDTransaction.toString) and the list of allowed statuses (HIDTransaction.getAllowedStatuses) that will be displayed to the end user so that they can decide which action to take (“approve” or “decline” the transaction).
  7. Display the transaction to the end user and retrieve the end user’s selection among the available statuses.
  8. Then request the end user to provide their Transaction Signing Protecting password and send the final status with optional mobile context data to the HID authentication platform (HIDTransaction.setStatus).

    For integrations with the HID Authentication Service, see User Authentication with HID Approve and the bcauthorize endpoint.

Sample Transaction Signing on iOS/macOS

Copy
do {
        // Get Device instance with default connection configuration
        let config = HIDConnectionConfiguration()
        let deviceFactory = HIDDeviceFactory.factory() as! HIDDeviceFactory
        let device = try deviceFactory.newInstance(config)
        
        // Get public information from the transaction identifier
        // the txId is obtainable either through the push message, or through the retrieveTransactionIds API of the container.
        let txInfo = try device.retrieveActionInfo(txId)
        
        // The public information includes the container and the transaction protection key.
        let container = try txInfo.getContainer()
        NSLog("Transaction is for container: %ld", container.getId());
        NSLog("Transaction unique id: %@", txInfo.getUniqueIdentifier());

        // We can check whether password is needed by getting the key and policy
        let key = try txInfo.getProtectionKey()
        NSLog("Transaction protection key is %@", key.getId().id);
        
        // Retrieve the transaction details
        // we assume session key is not password protected (password nil)
        let tx = try txInfo.getAction(nil, withParams: nil) as! HIDTransaction

        // The transaction contains the list of allowed response status
        let allowedStatus = tx.getAllowedStatuses()
        
        // Display transaction details to end user and request status
        NSLog("Transaction details %@", tx.toString());
        let txStatus = self.transactionPrompt(tx)
        
        // Here we can check whether the signing key is protected by a password
        var sigPassword: String?
        let sigKey = try tx.getSigningKey()
        let sigPolicy = try sigKey.getProtectionPolicy()
        if(sigPolicy.policyType()==HIDPolicyTypeBioPassword) {
            NSLog("Bio policy, check if it is enabled")
            let bioPolicy = sigPolicy as! HIDBioPasswordPolicy
            let bioState = bioPolicy.getBioAuthenticationState()
            if(bioState==HIDBioAuthenticationStateEnabled) {
                NSLog("Bio is enabled, password not needed")
                sigPassword = nil
            } else {
                NSLog("Bio is disabled, request password")
                sigPassword = self.passwordPrompt()
            }
        } else if(sigPolicy.policyType()==HIDPolicyTypePassword) {
            NSLog("Password policy, request password")
            sigPassword = self.passwordPrompt()
        } else {
            NSLog("No password")
            sigPassword = nil
        }
        
        // We can now sign the transaction with a selected status and context data
        let contextParam = HIDParameter(string: sContextB64, forKey: HID_PARAM_TX_MOBILE_CONTEXT)
        let params:[Any]? = [contextParam!]

        // we assume session key is not password protected (password nil)
        let isSigned = try tx.setStatus(txStatus, withSigningPassword: sigPassword, withSessionPassword: nil, withParams: params)
        NSLog("Transaction signed")
    }
    catch let error as NSError{
        NSLog("Failed to sign transaction: %@",error.localizedDescription);
    }
Copy
// Get Device instance with default connection configuration
    NSError* error;
    HIDConnectionConfiguration* connectionConfig = [[HIDConnectionConfiguration alloc] init];
    id<HIDDevice> pDevice = [[HIDDeviceFactory alloc] newInstance:connectionConfig error:&error];

    // Get public information from the transaction identifier
    // the txId is obtainable either through the push message, or through the retrieveTransactionIds API of the container.
    id<HIDServerActionInfo> txInfo = [pDevice retrieveActionInfo:txId error:&error];
    if (error)
    {
        NSLog(@"Failed to retrieve transaction info: %@ (%ld)",[error userInfo], (long)[error code]);
    }
    else {
        
        // The public information includes the container and the transaction protection key.
        id<HIDContainer> pContainer = [txInfo getContainer:&error];
        NSLog(@"Transaction is for container: %ld", (long)[pContainer getId]);
        NSLog(@"Transaction unique id: %@", [txInfo getUniqueIdentifier]);

        // We can check whether password is needed by getting the key and policy
        id<HIDKey> pKey = [txInfo getProtectionKey:&error];    
        NSLog(@"Transaction protection key is %@", [[pKey getId] ID]);
        
        // Retrieve the transaction details
        // we assume session key is not password protected (password nil)
        id<HIDTransaction> tx = ( id<HIDTransaction>)[txInfo getAction:nil withParams:nil error:&error];
        if (error) {
            NSLog(@"Failed to retrieve transaction: %@ (%ld)",[error description], (long)[error code]);
        }

        // The transaction contains the list of allowed response status    
        NSArray* allowedStatus = [tx getAllowedStatuses];
        
        // Display transaction details to end user and request status
        NSLog(@"Transaction details %@", [tx toString]);
        NSString* txStatus = [self transactionPrompt:tx];

        // Here we can check whether the signing key is protected by a password
        NSString* sigPassword = nil;
        id<HIDKey> pSigKey = [tx getSigningKey:&error];
        id<HIDProtectionPolicy>  sigPolicy = [pSigKey getProtectionPolicy:&error];
        if ([sigPolicy policyType] == HIDPolicyTypeBioPassword)
        {
            NSLog(@"Bio policy, check if it is enabled");
            id<HIDBioPasswordPolicy> bioPolicy = (id<HIDBioPasswordPolicy>)sigPolicy;
            HIDBioAuthenticationState bioState = [bioPolicy getBioAuthenticationState];
            if (bioState == HIDBioAuthenticationStateEnabled){
                NSLog(@"Bio is enabled, password not needed");
                sigPassword = nil;
            }
            else {
                NSLog(@"Bio is disabled, request password");
                sigPassword = [self passwordPrompt];
            }
        }
        else if ([sigPolicy policyType] == HIDPolicyTypePassword)
        {
            NSLog(@"Password policy, request password");
            sigPassword = [self passwordPrompt];
        }
        else {
            NSLog(@"No password");
            sigPassword = nil;
        }
        
        // We can now sign the transaction with a selected status and context data
        // optional parameter can be used to pass mobile context base64 data (otherwise leave empty or null)
        NSMutableArray* params = [NSMutableArray array];
        [params addObject:[HIDParameter parameterWithString:sContextB64 forKey: HID_PARAM_TX_MOBILE_CONTEXT]];

        // we assume session key is not password protected (password nil)
        BOOL isSigned = [tx setStatus:txStatus withSigningPassword:sigPassword withSessionPassword:nil withParams:params error:&error];
        if (error) {
            // HIDAuthentication if invalid password is given
            // HIDTransactionExpired if transaction is no longer valid
            // HIDPasswordExpired if password is expired and requires password change according to protection policy
            NSLog(@"Failed to sign transaction: %@ (%ld)",[error description], (long)[error code]);
        } else {
            NSLog(@"Transaction signed");
        }
    }