Last active
April 12, 2022 19:33
-
-
Save FeiChen-okta/b636e957a173fdec14f54c27cf3e4e19 to your computer and use it in GitHub Desktop.
oidc suspend coroutines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Oidc client using okta-oidc-android | |
* Instantiate this in the same activity for authenticate flow to prevent activity leaking | |
* | |
* @param activity | |
*/ | |
class OktaOidcClientImpl(app: Application, private val activity: AppCompatActivity? = null) { | |
constructor(app: Application) : this(app, null) | |
private val config = OIDCConfig.Builder() | |
.withJsonFile(activity, R.raw.config) | |
.create() | |
private val oidcClient = Okta.WebAuthBuilder() | |
.withConfig(config) | |
.withContext(activity ?: app) | |
.setRequireHardwareBackedKeyStore(false) | |
.create() | |
suspend fun oidcAuthenticate(payload: Map<String, String>): Result<String> { | |
return suspendCancellableCoroutine { continuation -> | |
val callback: ResultCallback<AuthorizationStatus, AuthorizationException> = | |
object : ResultCallback<AuthorizationStatus, AuthorizationException> { | |
override fun onSuccess(result: AuthorizationStatus) { | |
oidcClient?.unregisterCallback() | |
if (result == AuthorizationStatus.AUTHORIZED) { | |
oidcClient?.sessionClient?.tokens?.accessToken?.run { | |
continuation.resume(Result.success(this)) | |
} ?: continuation.resume(Result.failure(OidcError.NoSession)) | |
} else continuation.resume(Result.failure(OidcError.Unauthorized(result.name))) | |
} | |
override fun onCancel() { | |
oidcClient?.unregisterCallback() | |
continuation.resume(Result.failure(OidcError.Canceled)) | |
} | |
override fun onError(msg: String?, exception: AuthorizationException?) { | |
oidcClient?.unregisterCallback() | |
continuation.resume(Result.failure(OidcError.Error(msg, exception))) | |
} | |
} | |
continuation.invokeOnCancellation { continuation.resume(Result.failure(OidcError.Canceled)) } | |
activity?.run { | |
oidcClient?.run { | |
oidcClient.registerCallback(callback, activity) | |
val builder = AuthenticationPayload.Builder() | |
payload.forEach { builder.addParameter(it.key, it.value) } | |
oidcClient.signIn(activity, builder.build()) | |
} ?: continuation.resume(Result.failure(OidcError.InvalidState)) | |
} ?: continuation.resume(Result.failure(OidcError.InvalidState)) | |
} | |
} | |
suspend fun authToken(): Result<String> = runCatching { | |
oidcClient?.sessionClient?.tokens?.accessToken?.run { Result.success(this) } | |
?: Result.failure(IllegalStateException("Invalid oidc configuration")) | |
}.getOrElse { Result.failure(it) } | |
suspend fun refreshAccessToken(): Result<Tokens> = suspendCancellableCoroutine { continuation -> | |
val callback = object : RequestCallback<Tokens, AuthorizationException> { | |
override fun onSuccess(tokens: Tokens) = continuation.resume(Result.success(tokens)) | |
override fun onError(error: String?, exception: AuthorizationException?) { | |
continuation.resume(Result.failure(OidcError.Error(error, exception))) | |
} | |
} | |
continuation.invokeOnCancellation { continuation.resume(Result.failure(OidcError.Canceled)) } | |
oidcClient?.sessionClient?.run { refreshToken(callback) } ?: continuation.resume(Result.failure(OidcError.NoSession)) | |
} | |
suspend fun revokeAccessToken(): Result<Boolean> = suspendCancellableCoroutine { continuation -> | |
val callback = object : RequestCallback<Boolean, AuthorizationException> { | |
override fun onSuccess(result: Boolean) = continuation.resume(Result.success(result)) | |
override fun onError(error: String?, exception: AuthorizationException?) { | |
continuation.resume(Result.failure(exception ?: Exception(error))) | |
} | |
} | |
continuation.invokeOnCancellation { continuation.resume(Result.failure(OidcError.Canceled)) } | |
oidcClient?.sessionClient?.tokens?.run { oidcClient.sessionClient?.revokeToken(accessToken, callback) } | |
?: continuation.resume(Result.failure(OidcError.NoSession)) | |
} | |
fun clearData() { | |
oidcClient?.sessionClient?.clear() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment