Skip to content

wultra/networking-apple

Repository files navigation

PowerAuth Networking SDK for Apple platforms

Wultra Digital Onboarding for Apple Platforms

build spm pod date license

Wultra PowerAuth Networking (WPN) is a high-level SDK built on top of our PowerAuth SDK that enables request signing and encryption.

You can think of this SDK as an HTTP layer (client) that enables request signing and encryption via the PowerAuth SDK, based on its recommended implementation.

We use this SDK in our other open-source projects. You can use these as inspiration, for example:

Documentation Content

SDK Integration

Requirements

Swift Package Manager

Add the https://github.com/wultra/networking-apple repository as a package in the Xcode UI and add the WultraPowerAuthNetworking library as a dependency.

Alternatively, you can add the dependency manually. For example:

// swift-tools-version:5.9
import PackageDescription
let package = Package(
    name: "YourLibrary",
    platforms: [
        .iOS(.v13),
        .tvOS(.v13)
    ],
    products: [
        .library(
            name: "YourLibrary",
            targets: ["YourLibrary"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/wultra/networking-apple.git", .from("1.3.0"))
    ],
    targets: [
        .target(
            name: "YourLibrary",
            dependencies: ["WultraPowerAuthNetworking"]
        )
    ]
)

CocoaPods

Add the following dependency to your Podfile:

# CocoaPods integration currently targets iOS.
platform :ios, '13.0'

pod 'WultraPowerAuthNetworking'

Guaranteed PowerAuth Compatibility

WPN SDK PowerAuth SDK
1.5.x 1.9.x
1.4.x 1.8.x
1.3.x 1.8.x
1.0.x - 1.2.x 1.7.x

Xcode Compatibility

We recommend using Xcode version 26.0 or newer.

Open Source Code

The library is open source, and you can freely browse it on GitHub at https://github.com/wultra/networking-apple

Initialization and Configuration

Everything you need is packed into the single WPNNetworkingService class, which provides all the networking APIs you need.

To successfully create an instance of the service, you need only two things:

  • a configured PowerAuthSDK object
  • service configuration (such as the base endpoint URL)

You can create as many instances of the class as you need for your use case.

Example:

let networking = WPNNetworkingService(
    powerAuth: myPowerAuthInstance, // configured PowerAuthSDK instance
    config: WPNConfig(
        baseUrl: "https://sandbox.company.com/my-service", // URL to my PowerAuth based service
        sslValidation: .default, // use default SSL error handling (more in SSL validation docs section)
        timeoutIntervalForRequest: 10, // give 10 seconds for the server to respond
        userAgent: .libraryDefault // use library default HTTP User-Agent header
        
    ), 
    serviceName: "MyProjectNetworkingService", // for better debugging
    acceptLanguage: "en" // more info in "Language Configuration" docs section
)

Endpoint Definition

Each endpoint you target in your project must be defined for the service as a WPNEndpoint instance. There are several endpoint types, depending on the required PowerAuth signature.

End To End Encryption

If the endpoint is end-to-end encrypted, you need to configure it in the initializer. The default initializers use e2ee: .notEncrypted.

Possible values are:

/// Endpoint configuration for end to end encryption.
public enum WPNE2EEConfiguration {
    /// Endpoint is encrypted with the application scope.
    case applicationScope
    /// Endpoint is encrypted with the activation scope.
    case activationScope
    /// Endpoint is not encrypted.
    case notEncrypted
}

Whether an endpoint is encrypted is determined by its backend definition.

Signed endpoint WPNEndpointSigned

For endpoints that use a PowerAuth signature and can be end-to-end encrypted.

Example:

typealias MySignedEndpointType = WPNEndpointSigned<WPNRequest<MyEndpointDataRequest>, WPNResponse<MyEndpointDataResponse>>
var mySignedEndpoint: MySignedEndpointType { WPNEndpointSigned(endpointURLPath: "/additional/path/to/the/signed/endpoint", uriId: "endpoint/identifier", e2ee: .notEncrypted) }
// uriId is defined by the endpoint issuer - ask your server developer/provider

Signed endpoint with Token WPNEndpointSignedWithToken

For endpoints that use a PowerAuth token signature and can be end-to-end encrypted.

More information about token-based authentication can be found here.

Example:

typealias MyTokenEndpointType = WPNEndpointSignedWithToken<WPNRequest<MyEndpointDataRequest>, WPNResponse<MyEndpointDataResponse>>
var myTokenEndpoint: MyTokenEndpointType { WPNEndpointSignedWithToken(endpointURLPath: "/additional/path/to/the/token/signed/endpoint", tokenName: "MyToken", e2ee: .notEncrypted) }

// tokenName is the name of the token as stored in the PowerAuthSDK
// more information can be found in the PowerAuthSDK documentation
// https://github.com/wultra/powerauth-mobile-sdk/blob/develop/docs/PowerAuth-SDK-for-iOS.md#token-based-authentication

Basic endpoint (not signed) WPNEndpointBasic

For endpoints that do not use a PowerAuth signature but can still be end-to-end encrypted.

Example:

typealias MyBasicEndpointType = WPNEndpointBasic<WPNRequest<MyEndpointDataRequest>, WPNResponse<MyEndpointDataResponse>>
var myBasicEndpoint: MyBasicEndpointType { WPNEndpointBasic(endpointURLPath: "/additional/path/to/the/basic/endpoint", e2ee: .notEncrypted) }

Creating an HTTP request

To create an HTTP request for your endpoint, you can call either the callback-based WPNNetworkingService.post method or its async counterpart with the following request parameters:

  • data - the payload of your request
  • auth - the PowerAuthAuthentication instance used to sign the request
    • this parameter is omitted for the basic endpoint
  • endpoint - the endpoint to call
  • headers - custom HTTP headers, nil by default
  • timeoutInterval - the timeout interval, nil by default. When nil, the default configured in WPNConfig is used
  • progressCallback - a callback with percentage progress (values between 0 and 1)
  • completionQueue - the queue on which the completion is called (callback API only, main queue by default)
  • completion - the result completion handler (callback API only)

Example:

// payload we will send to the server
struct MyRequestPayload {
    let userID: String
}

// response of the server
struct MyResponse {
    let name: String
    let email: String
}

// endpoint configuration
typealias MyEndpointType = WPNEndpointSigned<WPNRequest<MyRequestPayload>, WPNResponse<MyResponse>>
var endpoint: MyEndpointType { WPNEndpointSigned(endpointURLPath: "/path/to/myendpoint", uriId: "myendpoint/identifier") }

// Authentication (for example purposes) expect user PIN 1111
let auth = PowerAuthAuthentication.possessionWithPassword("1111")
            
// WPNNetworkingService instance call
networking.post(
    // create request data
    data: MyEndpointType.RequestData(.init(userID: "12345")),
    // specify endpoint
    to: endpoint,
    // custom HTTP headers
    with: ["MyCustomHeader": "Value"],
    // only wait 10 seconds at max
    timeoutInterval: 10,
    // handle response or error
    completion: { result, error in
        if let data = result?.responseObject {
            // we have data
        } else {
            // handle error or empty response
        }
    }
)

WultraPowerAuthNetworking also provides async/await counterparts to all public WPNNetworkingService.post(...) overloads.

The SDK uses the system URLSession under the hood.

Raw Response Observer

All responses can be observed with WPNResponseDelegate in WPNNetworkingService.responseDelegate.

An example implementation of the delegate:

class MyResponseDelegateLogger: WPNResponseDelegate {
    
    func responseReceived(from url: URL, statusCode: Int?, body: Data) {
        print("Response received from \(url) with status code \(statusCode) and data:")
        print(String(data: body, encoding: .utf8) ?? "")
    }
    
    // for endpoints that are end-to-end encrypted
    func encryptedResponseReceived(from url: URL, statusCode: Int?, body: Data, decrypted: Data) {
        print("Encrypted response received from \(url) with status code \(statusCode) and: ")
        print("    Raw data:")
        print(String(data: body, encoding: .utf8) ?? "")
        print("    Decrypted data:")
        print(String(data: decrypted, encoding: .utf8) ?? "")
    }
}

Parallel Requests

By default, the SDK serializes all signed requests. Requests signed with PowerAuthSDK are placed into a queue and executed one by one, which means an HTTP request is not sent until the previous one finishes. Other requests are executed in parallel.

This behavior can be changed via WPNNetworkingService.concurrencyStrategy with the following possible values:

  • serialSigned - Default behavior. Only requests that need a PowerAuth signature will be put into the serial queue that is shared with the PowerAuthSDK instance to ensure all signed requests are in proper order.
  • concurrentAll - All requests will be put into the concurrent queue. This behavior is not recommended unless you know exactly why you want this.

More about this topic can be found in the PowerAuth documentation.

JSON encoder and decoder

The SDK uses JSONEncoder and JSONDecoder with iso8601 date strategies by default.

If the default configuration does not suit your needs, you can assign your own encoder and decoder instances to the jsonEncoder and jsonDecoder properties of WPNNetworkingService. They will then be used for all outbound and inbound traffic.

For more info about the JSON encoding and decoding, visit the official Apple documentation.

SSL validation

The SDK uses the system's default handling of SSL errors. To ignore SSL errors (for example, when your test server does not have a valid SSL certificate) or implement your own SSL pinning, configure the WPNConfig.sslValidation property.

Possible values are:

  • default - Uses default URLSession handling.
  • noValidation - Trust HTTPS connections with invalid certificates.
  • sslPinning(_ provider: WPNPinningProvider) - Validates the server certificate with your own logic.

Error Handling

Every error produced by this library is of type WPNError. This error contains the following information:

  • reason - A specific reason why the error happened. For more information, see the WPNErrorReason chapter.
  • nestedError - The original exception or error (if available) that caused this error.
  • httpStatusCode - If the error is a networking error, this property will provide the HTTP status code of the error.
  • httpUrlResponse - If the error is a networking error, this holds the original HTTP response received from the backend.
  • restApiError - If the error is a "well-known" API error, it will be filled here. For all available codes follow the source code.
  • networkIsNotReachable - Convenience property, informs about a state where the network is unavailable (based on the error type).
  • networkConnectionIsNotTrusted - Convenience property, informs about a TLS error.
  • powerAuthErrorResponse - If the error was caused by the PowerAuth error, you can retrieve it here.
  • powerAuthRestApiErrorCode - If the error was caused by the PowerAuth error, the error code of the original error will be available here.

WPNErrorReason

Each WPNError has a reason property that explains why the error was created. This can be useful when you are creating, for example, general error-handling or reporting logic, or when you are debugging the code.

General errors

Option Name Description
unknown Unknown fallback reason
missingActivation PowerAuth instance is missing an activation.

Network errors

Option Name Description
network_unknown When unknown (usually logic error) happened during networking.
network_generic Network error that indicates a generic network issue (for example server internal error).
network_errorStatusCode HTTP response code was different than 200 (success).
network_invalidResponseObject An unexpected response from the server.
network_invalidRequestObject Request is not valid. Such an object is not sent to the server.
network_signError When the signing of the request failed.
network_timeOut Request timed out
network_noInternetConnection Not connected to the internet.
network_badServerResponse Bad (malformed) HTTP server response. Probably an unexpected HTTP server error.
network_sslError SSL error. For detailed information, see the attached error object when available.

Custom Errors

WPNErrorReason is a struct that can also be created by other libraries, so the list above is not exhaustive. Such errors (in libraries developed by Wultra) are documented in their respective documentation, for example in the Mobile Token SDK documentation.

Language Configuration

Before using any SDK methods that call the backend, you should set the proper language. Properly translated content is served based on this configuration. This setting does not persist, so you need to set acceptLanguage every time the application starts.

Note: Content-language capabilities are limited by the server implementation - the server must support the provided language.

Format

The default value is always en. For other languages, use values compliant with the standard RFC Accept-Language.

Logging

You can set up logging for the library using the WPNLogger class.

Verbosity Level

You can limit the amount of logged information via the verboseLevel property.

Level Description
off Silences all logs.
errors Only errors will be logged.
warnings (default) Errors and warnings will be logged.
info Errors, warnings, and info messages will be logged.
debug All messages will be logged.

Character limit

To prevent huge logs from being printed, the default limit is 12,000 characters per log. You can change this via WPNLogger.characterLimit.

HTTP traffic logs

  • You can turn on or off logging of HTTP requests and responses with the WPNLogger.logHttpTraffic property.
  • You can filter which headers will be logged with the WPNLogger.httpHeadersToSkip property.

Logger Delegate

If you want to process logs on your own (for example, log them to a file or a cloud service), you can set WPNLogger.delegate.

Changelog

TBA

  • Raised the minimum supported platform versions to iOS 13.0 and tvOS 13.0.
  • Added async/await counterparts to all public WPNNetworkingService.post(...) overloads.

1.5.2

  • Time is now always synchronized when creating token-based authorization headers

1.5.1

  • Added jsonDecoder and jsonEncoder properties to the WPNNetworkingService for custom JSON formatting
  • Better iso8601 date deserialization by default
  • Improved async operation state handling + better cancel handling
  • Making WPNRequest Encodable instead of Codable

1.5.0

  • Upgraded PowerAuthSDK to 1.9.x (requires server 1.9+)
  • End-to-end encryption was moved from post functions to the endpoint definition

1.4.0

  • Log improvements
  • Removed the serialAll option from concurrency settings

1.3.2

  • Added new WPNKnownRestApiError cases

1.3.0

  • Upgraded PowerAuthSDK to 1.8.x (requires server 1.5+)

Web Documentation

This documentation is also available at the Wultra Developer Portal.

License

All sources are licensed using the Apache 2.0 license. You can use them with no restrictions. If you are using this library, please let us know. We will be happy to share and promote your project.

Contact

If you need any assistance, do not hesitate to drop us a line at hello@wultra.com or our official wultra.com/discord channel.

Security Disclosure

If you believe you have identified a security vulnerability with this SDK, you should report it as soon as possible via email to support@wultra.com. Please do not post it to a public issue tracker.

About

A high-level networking SDK for PowerAuth-based endpoints.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages