Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to associate the localhost domain with my application identifier when using Passkey auth?

Working a Vapor application on localhost, and when trying to authenticate with Passkey using the iPhone simulator, the authorizationController(controller:didCompleteWithError:) delegate method triggers this error:

["NSLocalizedFailureReason": Application with identifier <APP_BUNDLE_ID> is not associated with domain localhost:8080]

The setup on the Vapor project is:

  • The server starts on https://localhost:8080
  • The /.well-known/apple-app-site-association file is being reach through (Vapor/RouteLoggingMiddleware.swift:14).
{
  "applinks": {
    "details": [
      {
        "appIDs": ["<APP_BUNDLE_ID>"],
        "components": []
      }
    ]
   },
  "webcredentials": {
    "apps": ["<APP_BUNDLE_ID>"]
  }
}

There is proper communication with the server, as I can see the username of the user being received from the iPhone simulator request. The request sends back the userID and the Challenge to authenticate with Passkey.

The setup on the iOS project is:

  • Associated Domains is webcredentials:localhost:8080?mode=developer

The code to create the Passkey authentication:

  func authenticate(with email: String) async throws {

    let publicKeyProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(
      relyingPartyIdentifier: "localhost:8080"
    )

    // The authentication request to receive the `userID` and `Challenge`.
    // This part is sucessful.
    let authenticationData = AuthenticationData(email: email)
    let urlRequest = try urlRequest(with: authenticationData, atEndpoint: .authentication)
    let data = try await serverCall(for: PublicAuthKeyData.self, on: urlRequest)

    let registrationRequest = publicKeyProvider.createCredentialRegistrationRequest(
      challenge: data.challenge.decodeBase64(),
      name: email,
      userID: data.userID.decodeBase64()
    )

    let authController = ASAuthorizationController(
      authorizationRequests: [registrationRequest]
    )
    authController.delegate = self
    authController.presentationContextProvider = self
    authController.performRequests()
  }

From there, the authorizationController(controller:didCompleteWithError:) trigger the error Domain=com.apple.AuthenticationServices.AuthorizationError Code=1004

like image 839
Roland Lariotte Avatar asked Dec 17 '25 12:12

Roland Lariotte


2 Answers

Paskeys require verifying the domain with the app via the app sites association file. In order to do this the app needs to be able to make a network request over the internet to get the file so localhost won't work. You can use something like ngrok to expose a local service to the internet to make it work

like image 102
0xTim Avatar answered Dec 19 '25 04:12

0xTim


I've managed to get this working on macOS, with localhost. It's going to be long.

The accepted answer is simply not true. According to the documentation you set the ?mode=developer flag on your website to circumvent the Apple CDN when looking up the associated domain.

So, to make an associated domain localhost work locally, you would ideally need localhost?mode=developer.

1. Developer Mode

It's vaguely referred to, but "Developer Mode" must be set for the ?mode=developer flag to work. There is no official Apple documentation on how to set this for a mac, but by searching online, you can find the swcutil command-line tool.

Running sudo swcutil --help you can reveal the correct command is going to be:

$ sudo swcutil --verbose developer-mode -e true 

Always add the --verbose flag, or you might not understand your error, like SWCErrorDomain 1, which is "Xcode not installed".

2. Finding the correct domain which works locally

If you start a Terminal where you watch for logs from the swcd process by running sudo swcutil watch --verbose several mistakes can be revealed:

  • Trying 127.0.0.1?mode=developer

    Not going to work, because if you use this domain, you'll find a log message, saying "domain is an IP address, blocking".

  • Trying localhost?mode=developer

    Not going to work, because if you use this domain, you'll find a log message, saying "domain does not contain a period character".

  • Trying localhost.com?mode=developer

    Works.

3. Set localhost.com as your localhost alias

  • Go to /etc/hosts, and add a record to this file (do not delete records):

    127.0.0.1        localhost.com
    
  • Create an SSL cert and trust it with your system, according to this answer.

  • Serve this certificate and key on localhost.com according to this gist comment. Make sure you serve the .crt and the .key separately as suggested by the next comment after it.

  • Don't forget to include and serve the AASA file in the /.well-known/ folder.

Voila. You set up the associated domain to be used locally.


Now just create some credential (the Shiny example app is very good example):

[...]

let passkeyCredProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "localhost.com")

[...]

add the associated domain webcredentials:localhost.com?mode=developer to your app according to Apple Documentation.

And your Passkey request will appear:

enter image description here

like image 25
iSpain17 Avatar answered Dec 19 '25 02:12

iSpain17



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!