Skip to content

Commit e5176fc

Browse files
committed
Reverting passkey merge revert
This reverts commit 0e06b8c.
1 parent dcf37dd commit e5176fc

24 files changed

+1386
-44
lines changed

EXAMPLES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1242,4 +1242,5 @@ You might encounter errors similar to `PKIX path building failed: sun.security.p
12421242
The rules should be applied automatically if your application is using `minifyEnabled = true`. If you want to include them manually check the [proguard directory](proguard).
12431243
By default you should at least use the following files:
12441244
* `proguard-okio.pro`
1245-
* `proguard-gson.pro`
1245+
* `proguard-gson.pro`
1246+
* `proguard-jetpack.pro`

auth0/build.gradle

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,18 @@ version = getVersionFromFile()
3434
logger.lifecycle("Using version ${version} for ${name}")
3535

3636
android {
37-
compileSdkVersion 31
37+
compileSdkVersion 34
3838

3939
defaultConfig {
4040
minSdkVersion 21
41-
targetSdkVersion 31
41+
targetSdkVersion 34
4242
versionCode 1
4343
versionName project.version
4444

4545
buildConfigField "String", "LIBRARY_NAME", "\"$project.rootProject.name\""
4646
buildConfigField "String", "VERSION_NAME", "\"${project.version}\""
4747

48-
consumerProguardFiles '../proguard/proguard-gson.pro', '../proguard/proguard-okio.pro'
48+
consumerProguardFiles '../proguard/proguard-gson.pro', '../proguard/proguard-okio.pro', '../proguard/proguard-jetpack.pro'
4949
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
5050
}
5151
lintOptions {
@@ -77,13 +77,14 @@ ext {
7777
powermockVersion = '2.0.9'
7878
coroutinesVersion = '1.6.2'
7979
biometricLibraryVersion = '1.1.0'
80+
credentialManagerVersion = "1.3.0"
8081
}
8182

8283

8384
dependencies {
8485
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
8586
implementation 'androidx.core:core-ktx:1.6.0'
86-
implementation 'androidx.appcompat:appcompat:1.3.0'
87+
implementation 'androidx.appcompat:appcompat:1.6.0'
8788
implementation 'androidx.browser:browser:1.4.0'
8889
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
8990
implementation "com.squareup.okhttp3:okhttp:$okhttpVersion"
@@ -110,6 +111,9 @@ dependencies {
110111
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
111112

112113
testImplementation "androidx.biometric:biometric:$biometricLibraryVersion"
114+
115+
implementation "androidx.credentials:credentials-play-services-auth:$credentialManagerVersion"
116+
implementation "androidx.credentials:credentials:$credentialManagerVersion"
113117
}
114118

115119
apply from: rootProject.file('gradle/jacoco.gradle')

auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt

Lines changed: 118 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import com.auth0.android.request.internal.ResponseUtils.isNetworkError
1212
import com.auth0.android.result.Challenge
1313
import com.auth0.android.result.Credentials
1414
import com.auth0.android.result.DatabaseUser
15+
import com.auth0.android.result.PasskeyChallengeResponse
16+
import com.auth0.android.result.PasskeyRegistrationResponse
1517
import com.auth0.android.result.UserProfile
1618
import com.google.gson.Gson
1719
import okhttp3.HttpUrl.Companion.toHttpUrl
@@ -151,6 +153,102 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
151153
return loginWithToken(parameters)
152154
}
153155

156+
157+
/**
158+
* Log in a user using passkeys.
159+
* This should be called after the client has received the Passkey challenge and Auth-session from the server .
160+
* Requires the client to have the **Passkey** Grant Type enabled. See [Client Grant Types](https://auth0.com/docs/clients/client-grant-types)
161+
* to learn how to enable it.
162+
*
163+
* @param authSession the auth session received from the server as part of the public challenge request.
164+
* @param authResponse the public key credential response to be sent to the server
165+
* @param parameters additional parameters to be sent as part of the request
166+
* @return a request to configure and start that will yield [Credentials]
167+
*/
168+
internal fun signinWithPasskey(
169+
authSession: String,
170+
authResponse: PublicKeyCredentialResponse,
171+
parameters: Map<String, String>
172+
): AuthenticationRequest {
173+
val params = ParameterBuilder.newBuilder().apply {
174+
setGrantType(ParameterBuilder.GRANT_TYPE_PASSKEY)
175+
set(AUTH_SESSION_KEY, authSession)
176+
addAll(parameters)
177+
}.asDictionary()
178+
179+
return loginWithToken(params)
180+
.addParameter(
181+
AUTH_RESPONSE_KEY,
182+
Gson().toJsonTree(authResponse)
183+
) as AuthenticationRequest
184+
}
185+
186+
187+
/**
188+
* Register a user and returns a challenge.
189+
* Requires the client to have the **Passkey** Grant Type enabled. See [Client Grant Types](https://auth0.com/docs/clients/client-grant-types)
190+
* to learn how to enable it.
191+
*
192+
* @param userMetadata user information of the client
193+
* @param parameters additional parameter to be sent as part of the request
194+
* @return a request to configure and start that will yield [PasskeyRegistrationResponse]
195+
*/
196+
internal fun signupWithPasskey(
197+
userMetadata: UserMetadataRequest,
198+
parameters: Map<String, String>,
199+
): Request<PasskeyRegistrationResponse, AuthenticationException> {
200+
val user = Gson().toJsonTree(userMetadata)
201+
val url = auth0.getDomainUrl().toHttpUrl().newBuilder()
202+
.addPathSegment(PASSKEY_PATH)
203+
.addPathSegment(REGISTER_PATH)
204+
.build()
205+
206+
val params = ParameterBuilder.newBuilder().apply {
207+
setClientId(clientId)
208+
parameters[ParameterBuilder.REALM_KEY]?.let {
209+
setRealm(it)
210+
}
211+
}.asDictionary()
212+
213+
val passkeyRegistrationAdapter: JsonAdapter<PasskeyRegistrationResponse> = GsonAdapter(
214+
PasskeyRegistrationResponse::class.java, gson
215+
)
216+
val post = factory.post(url.toString(), passkeyRegistrationAdapter)
217+
.addParameters(params) as BaseRequest<PasskeyRegistrationResponse, AuthenticationException>
218+
post.addParameter(USER_PROFILE_KEY, user)
219+
return post
220+
}
221+
222+
223+
/**
224+
* Request for a challenge to initiate a passkey login flow
225+
* Requires the client to have the **Passkey** Grant Type enabled. See [Client Grant Types](https://auth0.com/docs/clients/client-grant-types)
226+
* to learn how to enable it.
227+
*
228+
* @param realm An optional connection name
229+
* @return a request to configure and start that will yield [PasskeyChallengeResponse]
230+
*/
231+
internal fun passkeyChallenge(
232+
realm: String?
233+
): Request<PasskeyChallengeResponse, AuthenticationException> {
234+
val url = auth0.getDomainUrl().toHttpUrl().newBuilder()
235+
.addPathSegment(PASSKEY_PATH)
236+
.addPathSegment(CHALLENGE_PATH)
237+
.build()
238+
239+
val parameters = ParameterBuilder.newBuilder().apply {
240+
setClientId(clientId)
241+
realm?.let { setRealm(it) }
242+
}.asDictionary()
243+
244+
val passkeyChallengeAdapter: JsonAdapter<PasskeyChallengeResponse> = GsonAdapter(
245+
PasskeyChallengeResponse::class.java, gson
246+
)
247+
248+
return factory.post(url.toString(), passkeyChallengeAdapter)
249+
.addParameters(parameters)
250+
}
251+
154252
/**
155253
* Log in a user using an Out Of Band authentication code after they have received the 'mfa_required' error.
156254
* The MFA token tells the server the username or email, password, and realm values sent on the first request.
@@ -695,8 +793,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
695793
val parameters = ParameterBuilder.newBuilder()
696794
.setClientId(clientId)
697795
.setGrantType(ParameterBuilder.GRANT_TYPE_AUTHORIZATION_CODE)
698-
.set(OAUTH_CODE_KEY, authorizationCode)
699-
.set(REDIRECT_URI_KEY, redirectUri)
796+
.set(OAUTH_CODE_KEY, authorizationCode).set(REDIRECT_URI_KEY, redirectUri)
700797
.set("code_verifier", codeVerifier)
701798
.asDictionary()
702799
val url = auth0.getDomainUrl().toHttpUrl().newBuilder()
@@ -736,26 +833,26 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
736833
.addPathSegment(OAUTH_PATH)
737834
.addPathSegment(TOKEN_PATH)
738835
.build()
739-
val requestParameters = ParameterBuilder.newBuilder()
740-
.setClientId(clientId)
741-
.addAll(parameters)
742-
.asDictionary()
836+
val requestParameters =
837+
ParameterBuilder.newBuilder()
838+
.setClientId(clientId)
839+
.addAll(parameters)
840+
.asDictionary()
743841
val credentialsAdapter: JsonAdapter<Credentials> = GsonAdapter(
744842
Credentials::class.java, gson
745843
)
746844
val request = BaseAuthenticationRequest(
747-
factory.post(url.toString(), credentialsAdapter),
748-
clientId,
749-
baseURL
845+
factory.post(url.toString(), credentialsAdapter), clientId, baseURL
750846
)
751847
request.addParameters(requestParameters)
752848
return request
753849
}
754850

755851
private fun profileRequest(): Request<UserProfile, AuthenticationException> {
756-
val url = auth0.getDomainUrl().toHttpUrl().newBuilder()
757-
.addPathSegment(USER_INFO_PATH)
758-
.build()
852+
val url =
853+
auth0.getDomainUrl().toHttpUrl().newBuilder()
854+
.addPathSegment(USER_INFO_PATH)
855+
.build()
759856
val userProfileAdapter: JsonAdapter<UserProfile> = GsonAdapter(
760857
UserProfile::class.java, gson
761858
)
@@ -782,6 +879,9 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
782879
private const val SUBJECT_TOKEN_KEY = "subject_token"
783880
private const val SUBJECT_TOKEN_TYPE_KEY = "subject_token_type"
784881
private const val USER_METADATA_KEY = "user_metadata"
882+
private const val AUTH_SESSION_KEY = "auth_session"
883+
private const val AUTH_RESPONSE_KEY = "authn_response"
884+
private const val USER_PROFILE_KEY = "user_profile"
785885
private const val SIGN_UP_PATH = "signup"
786886
private const val DB_CONNECTIONS_PATH = "dbconnections"
787887
private const val CHANGE_PASSWORD_PATH = "change_password"
@@ -793,24 +893,23 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
793893
private const val REVOKE_PATH = "revoke"
794894
private const val MFA_PATH = "mfa"
795895
private const val CHALLENGE_PATH = "challenge"
896+
private const val PASSKEY_PATH = "passkey"
897+
private const val REGISTER_PATH = "register"
796898
private const val HEADER_AUTHORIZATION = "Authorization"
797899
private const val WELL_KNOWN_PATH = ".well-known"
798900
private const val JWKS_FILE_PATH = "jwks.json"
799901
private fun createErrorAdapter(): ErrorAdapter<AuthenticationException> {
800902
val mapAdapter = forMap(GsonProvider.gson)
801903
return object : ErrorAdapter<AuthenticationException> {
802904
override fun fromRawResponse(
803-
statusCode: Int,
804-
bodyText: String,
805-
headers: Map<String, List<String>>
905+
statusCode: Int, bodyText: String, headers: Map<String, List<String>>
806906
): AuthenticationException {
807907
return AuthenticationException(bodyText, statusCode)
808908
}
809909

810910
@Throws(IOException::class)
811911
override fun fromJsonResponse(
812-
statusCode: Int,
813-
reader: Reader
912+
statusCode: Int, reader: Reader
814913
): AuthenticationException {
815914
val values = mapAdapter.fromJson(reader)
816915
return AuthenticationException(values, statusCode)
@@ -819,13 +918,11 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
819918
override fun fromException(cause: Throwable): AuthenticationException {
820919
if (isNetworkError(cause)) {
821920
return AuthenticationException(
822-
"Failed to execute the network request",
823-
NetworkErrorException(cause)
921+
"Failed to execute the network request", NetworkErrorException(cause)
824922
)
825923
}
826924
return AuthenticationException(
827-
"Something went wrong",
828-
Auth0Exception("Something went wrong", cause)
925+
"Something went wrong", Auth0Exception("Something went wrong", cause)
829926
)
830927
}
831928
}

auth0/src/main/java/com/auth0/android/authentication/ParameterBuilder.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ public class ParameterBuilder private constructor(parameters: Map<String, String
159159
"http://auth0.com/oauth/grant-type/passwordless/otp"
160160
public const val GRANT_TYPE_TOKEN_EXCHANGE: String =
161161
"urn:ietf:params:oauth:grant-type:token-exchange"
162+
public const val GRANT_TYPE_PASSKEY :String = "urn:okta:params:oauth:grant-type:webauthn"
162163
public const val SCOPE_OPENID: String = "openid"
163164
public const val SCOPE_OFFLINE_ACCESS: String = "openid offline_access"
164165
public const val SCOPE_KEY: String = "scope"

0 commit comments

Comments
 (0)