Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions descopesdk/src/main/java/com/descope/Descope.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.descope.sdk.DescopeOAuth
import com.descope.sdk.DescopeOtp
import com.descope.sdk.DescopePasskey
import com.descope.sdk.DescopePassword
import com.descope.sdk.DescopePush
import com.descope.sdk.DescopeSdk
import com.descope.sdk.DescopeSso
import com.descope.sdk.DescopeTotp
Expand Down Expand Up @@ -116,6 +117,10 @@ object Descope {
val password: DescopePassword
get() = sdk.password

/** Authentication with push notifications. */
val push: DescopePush
get() = sdk.push

/**
* Resumes an ongoing authentication that's waiting for an external authentication step.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import com.descope.types.SignUpDetails
import com.descope.types.UpdateOptions
import java.net.HttpCookie

internal open class DescopeClient(internal val config: DescopeConfig, systemInfo: SystemInfo) : HttpClient(config.baseUrl ?: baseUrlForProjectId(config.projectId), config.logger, config.networkClient) {
internal open class DescopeClient(internal val config: DescopeConfig, internal val systemInfo: SystemInfo) : HttpClient(config.baseUrl ?: baseUrlForProjectId(config.projectId), config.logger, config.networkClient) {

// OTP

Expand Down Expand Up @@ -461,6 +461,29 @@ internal open class DescopeClient(internal val config: DescopeConfig, systemInfo
),
)

// Push

suspend fun pushEnrollDevice(token: String, device: String, refreshJwt: String): Unit = post(
route = "auth/push/update",
decoder = emptyResponse,
headers = authorization(refreshJwt),
body = mapOf(
"provider" to "fcm",
"token" to token,
"device" to device,
),
)

suspend fun pushSignInFinish(transactionId: String, approved: Boolean, refreshJwt: String): Unit = post(
route = "auth/push/signin/finish",
decoder = emptyResponse,
headers = authorization(refreshJwt),
body = mapOf(
"transactionId" to transactionId,
"result" to if (approved) "approved" else "denied",
),
)

// Others

suspend fun me(refreshJwt: String): UserResponse = get(
Expand Down
15 changes: 15 additions & 0 deletions descopesdk/src/main/java/com/descope/internal/routes/Push.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.descope.internal.routes

import com.descope.internal.http.DescopeClient
import com.descope.sdk.DescopePush

internal class Push(private val client: DescopeClient) : DescopePush {

override suspend fun enroll(token: String, refreshJwt: String) {
client.pushEnrollDevice(token = token, device = client.systemInfo.device ?: "Android", refreshJwt = refreshJwt)
}

override suspend fun finish(transactionId: String, approved: Boolean, refreshJwt: String) {
client.pushSignInFinish(transactionId = transactionId, approved = approved, refreshJwt = refreshJwt)
Comment thread
shilgapira marked this conversation as resolved.
}
}
29 changes: 29 additions & 0 deletions descopesdk/src/main/java/com/descope/sdk/Routes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -956,3 +956,32 @@ interface DescopeFlow {
*/
data class Authentication(val flowId: String, val refreshJwt: String)
}

/**
* Authenticate users using push notifications.
*
* The push notification authentication works by registering the user's device
* via FCM (Firebase Cloud Messaging) and then completing authentication
* transactions by approving or denying them.
*/
interface DescopePush {
/**
* Registers an FCM device token for push authentication.
*
* The user must have an active [DescopeSession] whose [refreshJwt] should be
* passed as a parameter to this function.
*
* @param token the FCM device token to register.
* @param refreshJwt the refreshJwt from an active [DescopeSession].
*/
suspend fun enroll(token: String, refreshJwt: String)

/**
* Completes a push authentication transaction by approving or denying it.
*
* @param transactionId the ID of the push authentication transaction.
* @param approved whether the authentication request is approved or denied.
* @param refreshJwt the refreshJwt from an active [DescopeSession].
*/
suspend fun finish(transactionId: String, approved: Boolean, refreshJwt: String)
}
3 changes: 3 additions & 0 deletions descopesdk/src/main/java/com/descope/sdk/Sdk.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.descope.internal.routes.OAuth
import com.descope.internal.routes.Otp
import com.descope.internal.routes.Passkey
import com.descope.internal.routes.Password
import com.descope.internal.routes.Push
import com.descope.internal.routes.Sso
import com.descope.internal.routes.Totp
import com.descope.internal.others.with
Expand All @@ -36,6 +37,7 @@ class DescopeSdk(context: Context, projectId: String, configure: DescopeConfig.(
val sso: DescopeSso
val passkey: DescopePasskey
val password: DescopePassword
val push: DescopePush
@Deprecated(message = "Use DescopeFlowView instead")
val flow: DescopeFlow

Expand All @@ -62,6 +64,7 @@ class DescopeSdk(context: Context, projectId: String, configure: DescopeConfig.(
sso = Sso(client)
passkey = Passkey(client)
password = Password(client)
push = Push(client)
flow = Flow(client)
// init session manager
sessionManager = initDefaultManager(context, config)
Expand Down
Loading