Deliver Apple Passkey solutions to your users.
The IBM Security Verify Relying Party Kit for iOS is the client-side companion to IBM Security Verify Relying Party Server for Swift which exposes REST API's hosted in a Docker image.
RelyingPartyKit is a lightweight framework that provides the ability for existing users to register their device with Apple Passkey and subsequently sign-in without a password and for new users to sign-up and validate their account.
Go to the Apple Developer Site if you like to learn more about developing Passkey-enabled apps.
RelyingPartyKit is available as a Swift Package Manager package. To use it, specify the package as a dependency in your Xcode project or Package.swift
file:
.package(url: "https://github.com/ibm-security-verify/webauthn-relying-party-kit-ios.git")
This scenario is where the user doesn't exist in your identity system and requires ownership of an email address for validation.
import RelyingPartyKit
// The baseURL is the host of the relying party server.
let client = RelyingPartyClient(baseURL: URL(string: "https://example.com")!)
// The result is an OTPChallenge to correlate the email sent to the email address.
let result = try await client.signup(name: "Anne Johnson", email: "anne_johnson@icloud.com")
// Use the result.transactionId and the OTP value generated in the email to validate. If successful, the returned Token can be used to register for Passkey.
let token = try await client.validate(transactionId: result.transactionId, otp: "123456")
This scenario authenticates an existing user with a username and password.
import RelyingPartyKit
// The baseURL is the host of the relying party server.
let client = RelyingPartyClient(baseURL: URL(string: "https://example.com")!)
// The result is a Token which can be used to register for Passkey.
let token = try await client.authenticate(username: "anne_johnson@icloud.com", password: "a1b2c3d4")
This scenario requires the user to be authenticated with a valid Token
. Cookie-based authenticated user is available using the headers
parameter where supported by the relying party server. Registering for Passkey uses ASAuthorizationControllerDelegate to handle the result of the platform key registration request.
import RelyingPartyKit
// The baseURL is the host of the relying party server.
let client = RelyingPartyClient(baseURL: URL(string: "https://example.com")!)
let token = try await client.authenticate(username: "account@example.com", password: "a1b2c3d4")
let nickname = "Anne's iPhone"
// First generate a challenge from the relying party server.
let result: CredentialRegistrationOptions = try await client.challenge(displayName: nickname, token: token)
// Construct a request to the platform provider with the challenge. The challenge result contains the user identifier and name for Passkey registration.
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com")
let request = provider.createCredentialRegistrationRequest(challenge: result.challenge,
name: result.user.name,
userID: result.user.id)
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
// This will display the Passkey sheet for the user to continue with the registration. The outcome of the registration request is provided on the ASAuthorizationControllerDelegate.
controller.performRequests()
// Respond to the request
func authorizationController(controller: controller, didCompleteWithAuthorization: authorization) {
if let credential = authorization.credential as? ASAuthorizationPlatformPublicKeyCredentialRegistration {
// Take steps to handle the registration.
try await client.register(nickname: nickname,
clientDataJSON: credential.rawClientDataJSON,
attestationObject: credential.rawAttestationObject!,
credentialId: credential.credentialID,
token: token)
} else {
// Handle other authentication cases, such as Sign in with Apple.
}
}
This scenario is for users who have previously registered their device using Passkey. Similar to registering for Passkey, it uses ASAuthorizationControllerDelegate to handle the result of the platform key assertion request.
import RelyingPartyKit
// The baseURL is the host of the relying party server.
let client = RelyingPartyClient(baseURL: URL(string: "https://example.com")!)
// First generate a challenge from the relying party server.
let result: CredentialAssertionOptions = try await client.challenge()
// Construct a request to the platform provider with the challenge.
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com")
let request = provider.createCredentialAssertionRequest(challenge: result.challenge)
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
// This will show the Passkey sheet for the user to continue with the registration and provides the outcome of the registration request on the ASAuthorizationControllerDelegate.
controller.performRequests()
// Respond to the request
func authorizationController(controller: controller, didCompleteWithAuthorization: authorization) {
if let credential = authorization.credential as? ASAuthorizationPlatformPublicKeyCredentialAssertion {
// Take steps to handle the assertion.
let result: Token = try await client.signin(signature: credential.signature,
clientDataJSON: credential.rawClientDataJSON,
authenticatorData: credential.rawAuthenticatorData,
credentialId: credential.credentialID,
userId: credential.userID)
} else {
// Handle other authentication cases, such as Sign in with Apple.
}
}