Skip to content

First Account⚓︎

In this section, we walk through the steps required to enrol the first account. After scanning the enrol QR code, you need to start a flow and handle callbacks from the Mobile SDK. After these steps, you can proceed to do a QR based login or to move directly to AppLogin.

Scanning the (Enrol) QR Code⚓︎

The QR codes generated by the nextAuth Server contain binary data. Although iOS’s built-in QR code scanner can be configured to work with this data, Android has no native support for scanning QR codes. Therefore, the nextAuth Mobile SDK provides a security-focused QR code scanner that works by directly using the input of the camera. Note that the nextAuth QR code scanner only handles binary QR codes.

You may also choose to use a different QR code scanner as long as you can recover the raw binary data as received from the nextAuth Server.

Warning

If you do decide to use a third-party library for scanning QR codes, please ensure that it is actively maintained and that it has no unpatched security vulnerabilities.

Android⚓︎

Using androidx.camera, you can provide the output of the ImageAnalysis object as input for the NextAuth.processQR() method, which will in turn return a byte array containing the binary QR data if it detected a valid binary QR code in the input.

...
ImageAnalysis.Builder builder = new ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);

// recommended to set highest available resolution as there are some versions of 
// android that would otherwise crop to the upper right corner instead of 
// downsampling.
builder.setResolutionSelector(new ResolutionSelector.Builder()
    .setResolutionStrategy(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY).build());

ImageAnalysis imageAnalysis = builder.build();
imageAnalysis.setAnalyzer(cameraExecutor, image -> {
    // Use nextAuth's built-in QR code scanner
    final byte[] result = NextAuth.getNextAuth().processQR(image);
    image.close();
    if (result != null && result.length > 0) {
        // TODO: Handle the result (e.g. start a flow)
    }
});
...

Alternatively, you could use the BarcodeScanner class from Google’s ML Kit:

...
ImageAnalysis.Builder builder = new ImageAnalysis.Builder()
    .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);

// recommended to set highest available resolution as there are some versions of 
// android that would otherwise crop to the upper right corner instead of 
// downsampling.
builder.setResolutionSelector(new ResolutionSelector.Builder()
    .setResolutionStrategy(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY).build());

ImageAnalysis imageAnalysis = builder.build();

BarcodeScannerOptions options = new BarcodeScannerOptions.Builder()
    .setBarcodeFormats(Barcode.FORMAT_QR_CODE).build();
BarcodeScanner scanner = BarcodeScanning.getClient(options);

imageAnalysis.setAnalyzer(cameraExecutor, image -> {
    Image mediaImage = image.getImage();
    if (mediaImage != null) {
        InputImage inputImage = InputImage.fromMediaImage(mediaImage, 
            image.getImageInfo().getRotationDegrees());
        scanner.process(inputImage)
            .addOnSuccessListener(barcodes -> {
                if (!barcodes.isEmpty()) {
                    byte[] result = barcodes.get(0).getRawBytes();
                    if (result != null && result.length > 0) {
                        // TODO: Handle the result (e.g. start a flow)
                    }
                }
            })
            .addOnFailureListener(e -> image.close())
            .addOnCompleteListener(task -> image.close());
    }
});
...

iOS⚓︎

Although Apple’s Vision framework provides support for detecting a QR code, it does not directly support decoding the binary data contained therein. The following code demonstrates the recommended approach for processing the raw QR code descriptor.

...
func decode(barcodeDescriptor: CIQRCodeDescriptor) -> Data? {
    enum Mode: UInt8 {
        case byte = 0x04
    }

    guard let mode = Mode(rawValue: barcodeDescriptor.errorCorrectedPayload[0] >> 4), mode == .byte else {
        return nil
    }

    var location: Int
    var length: Int

    switch barcodeDescriptor.symbolVersion {
    case 1...9:
        location = 1
        length = Int((UInt16(barcodeDescriptor.errorCorrectedPayload[0] & 0x0f) << 4) | (UInt16(barcodeDescriptor.errorCorrectedPayload[1] & 0xf0) >> 4))

    case 10...40:
        location = 2
        length = Int((UInt16(barcodeDescriptor.errorCorrectedPayload[0] & 0x0f) << 12) | (UInt16(barcodeDescriptor.errorCorrectedPayload[1]) << 4) | (UInt16(barcodeDescriptor.errorCorrectedPayload[2] & 0xf0) >> 4))

    default:
        return nil
    }

    var data = Data()
    for i in location..<(location + length) {
        data.append((barcodeDescriptor.errorCorrectedPayload[i] << 4) | (barcodeDescriptor.errorCorrectedPayload[i+1] >> 4))
    }

    return data
}
...

Starting a Flow⚓︎

The Mobile SDK is built around the concept of flows. For the Mobile SDK to perform actions such as creating an account or logging in, you need to start a flow. This subsection describes how to start a flow based on the scanned QR code. Note that it is also possible to start a flow based on an incoming push message or deep link.

Android⚓︎

Start a flow by passing the decoded binary data (a byte array) obtained by scanning the QR code as input to the Mobile SDK:

byte[] data;
NextAuth.getNextAuth().getFlowManager().start(data);

iOS⚓︎

Start a flow by passing the decoded binary data obtained by scanning the QR code as input to the Mobile SDK:

var data: Data? = nil
flowService.start(with: data)

Handle Callbacks⚓︎

The expected sequence of FlowUpdate callbacks (for a given Flow with Type = ENROL) to be handled is as follows:

  1. State = PROCESSING -- the flow has started, but does not expect any input (yet). See here for more information.
  2. State = WAIT_FOR_INPUT and CurrentUserInteraction.Type = SET_SECOND_FACTOR -- asking the user to set their second factor. See here for more information.
  3. State = PROCESSING -- the nextAuth Mobile SDK is setting up the user’s account.
  4. State = DONE -- the flow successfully finished; the user is enrolled.

Info

In case the user already has an account in the nextAuth Mobile SDK, the user will not be asked to set up a second factor, but rather to verify their existing one.