PingOidc
module provides OIDC client for PingOne and ForgeRock platform.
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
let config = OidcClientConfig()
config.discoveryEndpoint = "https://auth.pingone.ca/02fb4743-189a-4bc7-9d6c-a919edfe6447/as/.well-known/openid-configuration"
config.clientId = "c12743f9-08e8-4420-a624-71bbb08e9fe1"
config.redirectUri = "org.forgerock.demo://oauth2redirect"
config.scopes = ["openid", "email", "address", "profile", "phone"]
let ping = OidcClient(config: config)
let result = await ping.token() // Retrieve the access token
switch result {
case .success(let token):
let accessToken = token
case .failure(let error):
switch error {
case .apiError:
//Address error
break
case .authorizeError:
//Address error
break
case .networkError:
//Address error
break
case .unknown:
//Address error
break
}
}
await ping.revoke() //Revoke the access token
_ = await ping.endSession() //End the session
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)
More OidcClient configuration, configurable attribute can be found under 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)