3.8 C
New York
Monday, February 24, 2025

swiftui – How you can intgrate Passkey in iOS App with customized Python backend utilizing WebAuthn


Intro
I’ve my very own backend serving API’s to Android and iOS Apps written Python utilizing the Flask framework.

I’ve succesfully managed to construct an Android App and API’s that talk with eachother that permits customers to register new passkeys and validate passkeys when signing in.

Now I am repeating this course of for iOS utilizing SwiftUI in Xcode 15.4 focusing on iOS 16.4 or increased. For this I’ve had a have a look at the Apple Meals Truck App instance (see: https://developer.apple.com/documentation/swiftui/food_truck_building_a_swiftui_multiplatform_app).

Passkey registration course of for Android
Following steps work tremendous on Android:

  1. Person needs to register a brand new passkey
  2. System requests a problem from the server
  3. Server receives request and makes use of the acquired customers e mail as title and fullname as displayname and generates a novel id as consumer id to generate the problem utilizing WebAuthn generate_registration_options
  4. The choices generated by WebAuth are ship again to the system as json
  5. The system creates a Public Key Credential Request, based mostly on the acquired choices containing the problem
  6. The consumer sees the system asking for affirmation to generate a passkey based mostly on biometrics (or no matter) and completes the passkey creation course of on the system
  7. The system sends the registration response json to the server
  8. The server verifies the acquired registration response utilizing WebAuth verify_registration_response operate. It makes use of the acquired registration response as enter even because the generated problem from step 3 as expected_challenge and the expected_origin formatted as “android:apk-key-hash:8363ghjjhg_blablabla_87234765^^%”
  9. The server replies again to the system if verification was a succes or not.

Problem
When I attempt to implement the identical steps within the iOS App I get caught on step 7 and eight. The WebAuthn validate_registration_response at all times comes again with “Shopper information problem was not anticipated problem”.

In steps 7 and eight I see variations into how Google and Apple applied these steps. It begins with that Android accepts the whole choices json that the generate_registration_options operate of WebAuthn produces. For iOS it appears that evidently I’ve to strip the problem out of this response and go it to:

    @Surroundings(.authorizationController) non-public var authorizationController

let authorizationResult = strive await authorizationController.performRequests(
                [passkeyRegistrationRequest(passkeyChallenge: passkeyChallenge, username: username, name: name)],
                    choices: choices)

non-public func passkeyRegistrationRequest(passkeyChallenge: Knowledge, username: String, title: String) async -> ASAuthorizationRequest {
        ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: Self.relyingPartyIdentifier)
           .createCredentialRegistrationRequest(problem: passkeyChallenge, title: title, userID: Knowledge(username.utf8))
    }

Described steps 5 & 6 are dealt with on this code, however once I find yourself at step 7 in code:

non-public func handleAuthorizationResult(_ authorizationResult: ASAuthorizationResult, username: String? = nil) async throws -> String {
        change authorizationResult {
        case let .password(passwordCredential):
            // Unused
            Logger.authorization.log("Password authorization succeeded: (passwordCredential)")
        case let .passkeyAssertion(passkeyAssertion):
            // Unused
            // The login was profitable.
            Logger.authorization.log("Passkey authorization succeeded: (passkeyAssertion)")
        case let .passkeyRegistration(passkeyRegistration):
            // The registration was profitable.
            Logger.authorization.log("Passkey registration succeeded: (passkeyRegistration")
                        
            guard let attestationObject = passkeyRegistration.rawAttestationObject else { return "" }
            let clientDataJSON = passkeyRegistration.rawClientDataJSON
            let credentialID = passkeyRegistration.credentialID
            
            // Construct the attestaion object
            let payload = ["rawId": credentialID.base64URLEncode(), // .base64EncodedString(), // Base64
                           "id": passkeyRegistration.credentialID.base64URLEncode(),
                           "authenticatorAttachment": "platform", // Optional parameter
                           "clientExtensionResults": [String: Any](), // Non-compulsory parameter
                           "sort": "public-key",
                           "response": [
                            "attestationObject": attestationObject.base64EncodedString(),
                            "clientDataJSON": clientDataJSON.base64EncodedString()
                           ]
            ] as [String: Any]
            
            var payloadJSONText = ""
            if let payloadJSONData = strive? JSONSerialization.information(withJSONObject: payload, choices: .fragmentsAllowed) {
                payloadJSONText = String(information: payloadJSONData, encoding: .utf8) ?? ""
            }

            Logger.authorization.log("Passkey registration succeeded 2: (payloadJSONText)")
            return payloadJSONText
        default:
            Logger.authorization.error("Obtained an unknown authorization end result.")
            // Throw an error and return to the caller.
            throw AuthorizationHandlingError.unknownAuthorizationResult(authorizationResult)
        }
        return ""
    }

In case let .passkeyRegistration(passkeyRegistration):, I ship the returned payload again to the server the place it must be validated utilizing WebAuthn verify_registration_response operate. However I have been capable of get this working.

The distinction right here is that I can see is that Android has an expected_origin of “android:apk-key-hash:8363ghjjhg_blablabla_87234765^^%” and for iOS it appears that evidently the origin is one thing like a URL format of my server that I used to create the problem with, however I am undecided right here.

What I attempted thus far
I additionally thought there might be points the place WebAuthn ought to count on one thing in base64url format as an alternative of base64, tried a number of combos of codecs for the sphere, however no luck.

I can not discover something thus far on the web that might assist me ahead with this. The whole lot I can discover is utilizing both iOS libraries or WebAuthn web providers and that it not what I need.

Plainly the validation on the server isn’t one thing that others do throughout the registration of a brand new passkey. Am I making an attempt to do the inconceivable right here?

As a result of this I have never even began with signing a consumer in, so I can not say at this second if there may be any concern there.

Who may help me within the right course?

Related Articles

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles