VPN: Password Reference

I noticed that I need not set the NEVPNProtocolIKEv2's passwordReference if I supplied the userName and password via the options argument in startVPNTunnel.

Supply password using passwordReference (requires use of Keychain):

func connect(userName: String, password: String, serverAddress: String) async throws {
    saveToKeychain(key: "VPN_Password", value: password)
    let passwordReference = keychainReference(key: "VPN_Password")

    let vpn = NEVPNManager.shared()
    try await vpn.loadFromPreferences()
    let pc = NEVPNProtocolIKEv2()
    pc.serverAddress = serverAddress
    pc.authenticationMethod = .none
    pc.username = userName
    pc.passwordReference = passwordReference
    pc.useExtendedAuthentication = true
    vpn.protocolConfiguration = pc
    vpn.isEnabled = true
    try await vpn.saveToPreferences()
    try await vpn.loadFromPreferences()
    try vpn.connection.startVPNTunnel()
}

Supply password using options parameter in startVPNTunnel:

func connect(userName: String, password: String, serverAddress: String) async throws {
    let vpn = NEVPNManager.shared()
    try await vpn.loadFromPreferences()
    let pc = NEVPNProtocolIKEv2()
    pc.serverAddress = serverAddress
    pc.authenticationMethod = .none
    pc.useExtendedAuthentication = true
    vpn.protocolConfiguration = pc
    vpn.isEnabled = true
    try await vpn.saveToPreferences()
    try await vpn.loadFromPreferences()
    try vpn.connection.startVPNTunnel(options: [NEVPNConnectionStartOptionUsername: userName, NEVPNConnectionStartOptionPassword: password])
}

Is one preferred over the other? I'm inclined to use the second one as it doesn't require the (additional) use of the Keychain. Are there any drawbacks in doing do?

Accepted Reply

When is it appropriate to use the second approach?

Honestly, not very often. Most users don’t launch your app to start the VPN connection. Rather, they start it from a system UI or using VPN On Demand. In that case the password has to be available in the keychain because your main app is not running at the time that the system starts the connection.

The second approach only makes sense if your VPN is structured such that the user has to start it from your app. That’s a pretty clunky user experience IMO.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

I'm inclined to use the second one as it doesn't require the (additional) use of the Keychain.

I’m confused by this position. The keychain is the best place to store user secrets. If you’re not storing this secret in the keychain, where are you storing it?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

They may rely on a credential provider or even a keychain entry tied to an auth context - I can't be sure. However, my question isn't about keychain; it is specifically about the differences between the two approaches. When is it appropriate to use the second approach?

When is it appropriate to use the second approach?

Honestly, not very often. Most users don’t launch your app to start the VPN connection. Rather, they start it from a system UI or using VPN On Demand. In that case the password has to be available in the keychain because your main app is not running at the time that the system starts the connection.

The second approach only makes sense if your VPN is structured such that the user has to start it from your app. That’s a pretty clunky user experience IMO.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"