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:
https://localhost:8080/.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:
webcredentials:localhost:8080?mode=developerThe 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
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
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.
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".
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.
localhost.com as your localhost aliasGo 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.
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:

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