Logo


PingOidc module provides a generic OIDC client that can be used with PingOne and ForgeRock platforms.

The PingOidc module follows the OIDC specification and provides a simple and easy-to-use API to interact with the OIDC server. It allows you to authenticate, retrieve the access token, revoke the token, and sign out from the OIDC server.

Integrating the SDK into your project

Use Cocoapods or Swift Package Manager

Oidc Client Configuration

Basic Configuration, use discoveryEndpoint to lookup OIDC endpoints

// Create an OIDC client with the discovery endpoint, and other configurations
public let oidcLogin = OidcWeb.createOidcWeb { config in
    config.module(PingOidc.OidcModule.config) { oidcValue in
        oidcValue.clientId = "ClientID"
        oidcValue.scopes = ["openid", "email", "address", "profile", "phone"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.discoveryEndpoint = "https://example.com/.well-known/openid-configuration"
    }
}

//Start the OIDC authentication flow
let state = try await oidcLogin.authorize { options in
    // Pass additional parameters
    options.additionalParameters = ["foo": "bar"]
}

// Handle the state
switch oidcLogin.state {
case .success( _ ):
    ...
case .failure(let error):
    ...
case .none:
    ...
}

// To retrieve the existing user
let oidcLoginUser = await oidcLogin.oidcLoginUser()

// To receive the access token
let token = await oidcLoginUser.token()

// Other methods
oidcLoginUser?.revoke()
oidcLoginUser?.logout()

// Setting the browser type and mode
public let oidcLogin = OidcWeb.createOidcWeb { config in
    // Set the browser mode(only the .login mode supported currently) and browser type.
    config.browserMode = .login
    config.browserType = .authSession
    config.module(PingOidc.OidcModule.config) { oidcValue in
        oidcValue.clientId = "ClientID"
        oidcValue.scopes = ["openid", "email", "address", "profile", "phone"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.discoveryEndpoint = "https://example.com/.well-known/openid-configuration"
    }
}

By default, the SDK uses KeychainStorage (with SecuredKeyEncryptor) to store the token and none Logger is set, however developers can override the storage and logger settings.

Basic Configuration with custom storage and logger

let config = OidcClientConfig()
config.logger = LogManager.standard //Log to console
config.storage = CustomStorage<Token>() //Use Custom Storage
//...

let ping = OidcClient(config: config)

Advanced OIDC Configuration

Configurable attributes can be found under the OIDC Spec

let config = OidcClientConfig()
config.acrValues = "urn:acr:form"
config.loginHint = "test"
config.display = "test"
//...

let ping = OidcClient(config: config)

Custom Agent

You can also provide a custom agent to launch the authorization request. You can implement the Agent interface to create a custom agent.

protocol Agent<T> {
     associatedtype T

     func config() -> () -> T
     func endSession(oidcConfig: OidcConfig<T>, idToken: String) async throws -> Bool
     func authorize(oidcConfig: OidcConfig<T>) async throws -> AuthCode
}

Here is an example of creating a custom agent.

//Create a custom agent configuration
struct CustomAgentConfig {
    var config1 = "config1Value"
    var config2 = "config2Value"
}

class CustomAgent: Agent {
    func config() -> () -> CustomAgentConfig {
        return { CustomAgentConfig() }
    }

    func authorize(oidcConfig: Oidc.OidcConfig<T>) async throws -> Oidc.AuthCode {
        oidcConfig.config.config2 //Access the agent configuration
        oidcConfig.oidcClientConfig.openId?.endSessionEndpoint //Access the oidcClientConfig
        return AuthCode(code: "TestAgent", codeVerifier: "")
    }

    func endSession(oidcConfig: Oidc.OidcConfig<CustomAgentConfig>, idToken: String) async throws -> Bool {
        //Logout session with idToken
        oidcConfig.config.config1 //Access the agent configuration
        oidcConfig.oidcClientConfig.openId?.endSessionEndpoint //Access the oidcClientConfig
        return true
    }
}

let config = OidcClientConfig()
config.updateAgent(CustomAgent())
//...

let ping = OidcClient(config: config)