Handling 2FA Push

Use Hyphen API to handle 2FA request push

Hyphen uses Firebase Messaging to send a 2-factor authorization request to the user's device. Without using SDK, your client needs to handle and implement the data sent along with the push message and display appropriate UI to the user.

Common Data Format

In the push message, there are fields that indicate whether the message is from Hyphen and which type is it. The actual data is always encoded as JSON and wrapped in a hyphen:data key in the push message.

Key
Description
Example

hyphen:type

The message type

"2fa-request"

hyphen:data

JSON-encoded data object

"{\"twoFactorAuth\":...}"

For example, on iOS, the data can be decoded like this:

struct TwoFactorAuthStatusPayload: Codable { ...}

func application(
    _ application: UIApplication,
    didReceiveRemoteNotification userInfo: [AnyHashable : Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
    guard let msgType = userInfo["hyphen:type"] as? String,
        let msgDataString = userInfo["hyphen:data"] as? String,
        let msgData = msgDataString.data(using: .utf8) else {
        // The payload was not a string or the string could not be converted to Data
        completionHandler(.failed)
        return
    }
    do {
        let decoder = JSONDecoder()
        switch msgType {
        case "2fa-status-change":
            let myData = try decoder.decode(TwoFactorAuthStatusPayload.self, from: msgData) 
            completionHandler(.myData)
        }
    } catch {
        print("Decoding error: \(error)")
        completionHandler(.failed)
    }
}

List of Push Message Data

2FA Request (On Destination Device)

This message is being sent to the destination device which approves/denies the 2FA request (e.g. the existing device having a key registered). It's sent as a notification with the highest priority.

Data Format

The hyphen:type is "2fa-request" .

Key
Description
Example

twoFactorAuth

TwoFactorAuthStatus object used same as REST API's.

{"id": "faceb00c-cafe-babe-badd-deadbeef1234", "app": ...}

Example

{
  "twoFactorAuth": {
    "id": "faceb00c-cafe-babe-badd-deadbeef1234",
    "status": "pending",
    "expiresAt": "2023-07-21T18:36:27.872Z",
    "request": {
      "id": "faceb00c-cafe-babe-badd-deadbeef1234",
      "app": {"appId": "swirl-dev", "appName": "Swirl"},
      "userOpInfo": {
        "type": "sign-in",
        "signIn": {
          "email": "john@acme.com",
          "ip": "127.0.0.1",
          "location": "Seoul, Korea"
        }
      },
      "message": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
      "srcDevice": {
        "publicKey": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
        "pushToken": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
        "name": "iPhone 14",
        "osName": "iOS",
        "osVersion": "16.2",
        "deviceManufacturer": "Apple",
        "deviceModel": "SM-265N",
        "lang": "en",
        "type": "mobile"
      },
      "destDevice": {
        "publicKey": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
        "pushToken": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
        "name": "iPhone 14",
        "osName": "iOS",
        "osVersion": "16.2",
        "deviceManufacturer": "Apple",
        "deviceModel": "SM-265N",
        "lang": "en",
        "type": "mobile"
      },
      "requestedAt": "2023-07-21T18:31:27.872Z"
    }
  }
}

2FA Status Change (On Source Device)

This message is being sent to the source device which requested the 2FA (e.g. the new device tries to sign in). It's sent as a Background Update push without any notification.

Data Format

The hyphen:type is "2fa-status-change" .

Key
Description
Example

twoFactorAuth

TwoFactorAuthStatus object used same as REST API's.

{"id": "faceb00c-cafe-babe-badd-deadbeef1234", "app": ...}

Example

If the user approves, the twoFactorAuth.result.txId field will contain the new key registration transaction sent from the destination device.

{
  "twoFactorAuth": {
    "id": "faceb00c-cafe-babe-badd-deadbeef1234",
    "status": "approved",
    "result": {
      "txId": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de"
    }
    "expiresAt": "2023-07-21T18:36:27.872Z",
    "request": {
      "id": "faceb00c-cafe-babe-badd-deadbeef1234",
      "app": {"appId": "swirl-dev", "appName": "Swirl"},
      "userOpInfo": {
        "type": "sign-in",
        "signIn": {
          "email": "john@acme.com",
          "ip": "127.0.0.1",
          "location": "Seoul, Korea"
        }
      },
      "message": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
      "srcDevice": {
        "publicKey": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
        "pushToken": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
        "name": "iPhone 14",
        "osName": "iOS",
        "osVersion": "16.2",
        "deviceManufacturer": "Apple",
        "deviceModel": "SM-265N",
        "lang": "en",
        "type": "mobile"
      },
      "destDevice": {
        "publicKey": "faceb00ccafebabedeadbeefbadf00defaceb00ccafebabedeadbeefbadf00de",
        "pushToken": "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
        "name": "iPhone 14",
        "osName": "iOS",
        "osVersion": "16.2",
        "deviceManufacturer": "Apple",
        "deviceModel": "SM-265N",
        "lang": "en",
        "type": "mobile"
      },
      "requestedAt": "2023-07-21T18:31:27.872Z"
    }
  }
}

Last updated

Was this helpful?