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:
- SDK Integration
- Open Source Code
- Initialization and Configuration
- Endpoint Definition
- Creating an HTTP request
- Raw Response Observer
- Parallel Requests
- SSL validation
- JSON encoder and decoder
- Error Handling
- Language Configuration
- Logging
- Changelog
- iOS 13.0+ and tvOS 13.0+
- PowerAuth Mobile SDK must already be integrated into your project
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"]
)
]
)Add the following dependency to your Podfile:
# CocoaPods integration currently targets iOS.
platform :ios, '13.0'
pod 'WultraPowerAuthNetworking'| 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 |
We recommend using Xcode version 26.0 or newer.
The library is open source, and you can freely browse it on GitHub at https://github.com/wultra/networking-apple
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
PowerAuthSDKobject - 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
)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.
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.
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/providerFor 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-authenticationFor 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) }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 requestauth- thePowerAuthAuthenticationinstance used to sign the request- this parameter is omitted for the basic endpoint
endpoint- the endpoint to callheaders- custom HTTP headers,nilby defaulttimeoutInterval- the timeout interval,nilby default. Whennil, the default configured inWPNConfigis usedprogressCallback- 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.
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) ?? "")
}
}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 thePowerAuthSDKinstance 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.
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.
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.
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.
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.
| Option Name | Description |
|---|---|
unknown |
Unknown fallback reason |
missingActivation |
PowerAuth instance is missing an activation. |
| 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. |
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.
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.
The default value is always en. For other languages, use values compliant with the standard RFC Accept-Language.
You can set up logging for the library using the WPNLogger class.
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. |
To prevent huge logs from being printed, the default limit is 12,000 characters per log. You can change this via WPNLogger.characterLimit.
- You can turn on or off logging of HTTP requests and responses with the
WPNLogger.logHttpTrafficproperty. - You can filter which headers will be logged with the
WPNLogger.httpHeadersToSkipproperty.
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.
- Raised the minimum supported platform versions to iOS 13.0 and tvOS 13.0.
- Added
async/awaitcounterparts to all publicWPNNetworkingService.post(...)overloads.
- Time is now always synchronized when creating token-based authorization headers
- Added
jsonDecoderandjsonEncoderproperties to theWPNNetworkingServicefor custom JSON formatting - Better
iso8601date deserialization by default - Improved async operation state handling + better cancel handling
- Making
WPNRequestEncodableinstead ofCodable
- Upgraded PowerAuthSDK to
1.9.x(requires server 1.9+) - End-to-end encryption was moved from post functions to the endpoint definition
- Log improvements
- Removed the
serialAlloption from concurrency settings
- Added new
WPNKnownRestApiErrorcases
- Upgraded PowerAuthSDK to
1.8.x(requires server 1.5+)
This documentation is also available at the Wultra Developer Portal.
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.
If you need any assistance, do not hesitate to drop us a line at hello@wultra.com or our official wultra.com/discord channel.
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.
