Skip to content

Commit

Permalink
Support Process Death in WebAuthProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
ahibrahimleague committed Feb 10, 2025
1 parent d5d2597 commit 98166b1
Show file tree
Hide file tree
Showing 24 changed files with 778 additions and 77 deletions.
12 changes: 5 additions & 7 deletions .github/actions/maven-publish/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ runs:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Java
shell: bash
run: |
curl -s "https://get.sdkman.io" | bash
source "/home/runner/.sdkman/bin/sdkman-init.sh"
sdk list java
sdk install java ${{ inputs.java-version }} && sdk default java ${{ inputs.java-version }}
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'

- uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4 # [email protected]

Expand Down
8 changes: 6 additions & 2 deletions .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ runs:
using: composite

steps:
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'

- run: |
curl -s "https://get.sdkman.io" | bash
source "/home/runner/.sdkman/bin/sdkman-init.sh"
sdk list java
sdk install java ${{ inputs.java }} && sdk default java ${{ inputs.java }}
sdk install gradle ${{ inputs.gradle }} && sdk default gradle ${{ inputs.gradle }}
sdk install kotlin ${{ inputs.kotlin }} && sdk default kotlin ${{ inputs.kotlin }}
shell: bash
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ jobs:
- if: github.actor == 'dependabot[bot]' || github.event_name == 'merge_group'
run: exit 0 # Skip unnecessary test runs for dependabot and merge queues. Artifically flag as successful, as this is a required check for branch protection.

- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '11'

- name: Checkout
uses: actions/checkout@v4

Expand Down
43 changes: 0 additions & 43 deletions .github/workflows/snyk.yml

This file was deleted.

6 changes: 3 additions & 3 deletions .snyk
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ ignore:
SNYK-JAVA-COMFASTERXMLWOODSTOX-3091135:
- '*':
reason: Latest version of dokka has this vulnerability
expires: 2024-12-31T12:54:23.000Z
expires: 2025-02-21T12:54:23.000Z
created: 2024-08-01T12:08:37.770Z
SNYK-JAVA-ORGJETBRAINSKOTLIN-2393744:
- '*':
reason: Latest version of dokka has this vulnerability
expires: 2024-12-31T12:54:23.000Z
expires: 2025-02-21T12:54:23.000Z
created: 2024-08-01T12:08:55.927Z
SNYK-JAVA-COMFASTERXMLJACKSONCORE-7569538:
- '*':
reason: Latest version of dokka has this vulnerability
expires: 2024-12-31T1:54:23.000Z
expires: 2025-02-21T1:54:23.000Z
created: 2024-08-01T12:08:02.973Z
patch: {}
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.2.0
3.3.0
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Change Log

## [3.3.0](https://github.com/auth0/Auth0.Android/tree/3.3.0) (2025-02-03)
[Full Changelog](https://github.com/auth0/Auth0.Android/compare/3.2.1...3.3.0)

**Added**
- Add support for custom token exchange [\#789](https://github.com/auth0/Auth0.Android/pull/789) ([pmathew92](https://github.com/pmathew92))

## [3.2.1](https://github.com/auth0/Auth0.Android/tree/3.2.1) (2024-12-06)
[Full Changelog](https://github.com/auth0/Auth0.Android/compare/3.2.0...3.2.1)

**Added**
- Added new error types for CredentialsManagerException [\#783](https://github.com/auth0/Auth0.Android/pull/783) ([pmathew92](https://github.com/pmathew92))
- Making realm parameter optional for passkeys [\#776](https://github.com/auth0/Auth0.Android/pull/776) ([pmathew92](https://github.com/pmathew92))

## [3.2.0](https://github.com/auth0/Auth0.Android/tree/3.2.0) (2024-11-07)
[Full Changelog](https://github.com/auth0/Auth0.Android/compare/3.1.0...3.2.0)

Expand Down
52 changes: 52 additions & 0 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- [Step 2: Input the code](#step-2-input-the-code)
- [Sign Up with a database connection](#sign-up-with-a-database-connection)
- [Get user information](#get-user-information)
- [Custom Token Exchange](#custom-token-exchange)
- [Credentials Manager](#credentials-manager)
- [Secure Credentials Manager](#secure-credentials-manager)
- [Usage](#usage)
Expand Down Expand Up @@ -487,6 +488,57 @@ authentication
```
</details>

### Custom Token Exchange

```kotlin
authentication
.customTokenExchange("subject_token_type", "subject_token")
.start(object : Callback<Credentials, AuthenticationException> {
override fun onSuccess(result: Credentials) {
// Handle success
}

override fun onFailure(exception: AuthenticationException) {
// Handle error
}

})
```
<details>
<summary>Using coroutines</summary>

``` kotlin
try {
val credentials = authentication
.tokenExchange("subject_token_type", "subject_token")
.await()
} catch (e: AuthenticationException) {
e.printStacktrace()
}
```
</details>

<details>
<summary>Using Java</summary>

```java
authentication
.customTokenExchange("subject_token_type", "subject_token")
.start(new Callback<Credentials, AuthenticationException>() {
@Override
public void onSuccess(@Nullable Credentials payload) {
// Handle success
}
@Override
public void onFailure(@NonNull AuthenticationException error) {
// Handle error
}
});
```


</details>


## Credentials Manager

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ To install Auth0.Android with [Gradle](https://gradle.org/), simply add the foll

```gradle
dependencies {
implementation 'com.auth0.android:auth0:3.2.0'
implementation 'com.auth0.android:auth0:3.3.0'
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* ```
* client.signinWithPasskey("{authSession}", "{authResponse}","{realm}")
* .validateClaims() //mandatory
* .addParameter("scope","scope")
* .setScope("{scope}")
* .start(object: Callback<Credentials, AuthenticationException> {
* override fun onFailure(error: AuthenticationException) { }
* override fun onSuccess(result: Credentials) { }
Expand Down Expand Up @@ -211,7 +211,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* ```
* client.signinWithPasskey("{authSession}", "{authResponse}","{realm}")
* .validateClaims() //mandatory
* .addParameter("scope","scope")
* .setScope("{scope}")
* .start(object: Callback<Credentials, AuthenticationException> {
* override fun onFailure(error: AuthenticationException) { }
* override fun onSuccess(result: Credentials) { }
Expand Down Expand Up @@ -457,13 +457,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
* @return a request to configure and start that will yield [Credentials]
*/
public fun loginWithNativeSocialToken(token: String, tokenType: String): AuthenticationRequest {
val parameters = ParameterBuilder.newAuthenticationBuilder()
.setGrantType(ParameterBuilder.GRANT_TYPE_TOKEN_EXCHANGE)
.setClientId(clientId)
.set(SUBJECT_TOKEN_KEY, token)
.set(SUBJECT_TOKEN_TYPE_KEY, tokenType)
.asDictionary()
return loginWithToken(parameters)
return tokenExchange(tokenType, token)
}

/**
Expand Down Expand Up @@ -707,6 +701,34 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
.addParameters(parameters)
}

/**
* The Custom Token Exchange feature allows clients to exchange their existing tokens for Auth0 tokens by calling the `/oauth/token` endpoint with specific parameters.
* The default scope used is 'openid profile email'.
*
* Example usage:
*
* ```
* client.customTokenExchange("{subject token type}", "{subject token}")
* .validateClaims() //mandatory
* .setScope("{scope}")
* .setAudience("{audience}")
* .start(object: Callback<Credentials, AuthenticationException> {
* override fun onSuccess(result: Credentials) { }
* override fun onFailure(error: AuthenticationException) { }
* })
* ```
*
* @param subjectTokenType the subject token type that is associated with the existing Identity Provider. e.g. 'http://acme.com/legacy-token'
* @param subjectToken the subject token, typically obtained through the Identity Provider's SDK
* @return a request to configure and start that will yield [Credentials]
*/
public fun customTokenExchange(
subjectTokenType: String,
subjectToken: String,
): AuthenticationRequest {
return tokenExchange(subjectTokenType, subjectToken)
}

/**
* Requests new Credentials using a valid Refresh Token. The received token will have the same audience and scope as first requested.
*
Expand Down Expand Up @@ -922,6 +944,21 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
return request
}

/**
* Helper function to make a request to the /oauth/token endpoint with the token exchange grant type.
*/
private fun tokenExchange(
subjectTokenType: String,
subjectToken: String
): AuthenticationRequest {
val parameters = ParameterBuilder.newAuthenticationBuilder()
.setGrantType(ParameterBuilder.GRANT_TYPE_TOKEN_EXCHANGE)
.set(SUBJECT_TOKEN_TYPE_KEY, subjectTokenType)
.set(SUBJECT_TOKEN_KEY, subjectToken)
.asDictionary()
return loginWithToken(parameters)
}

private fun profileRequest(): Request<UserProfile, AuthenticationException> {
val url =
auth0.getDomainUrl().toHttpUrl().newBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,15 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
saveCredentials(credentials)
callback.onSuccess(credentials)
} catch (error: AuthenticationException) {
val exception = when {
error.isRefreshTokenDeleted ||
error.isInvalidRefreshToken -> CredentialsManagerException.Code.RENEW_FAILED
error.isNetworkError -> CredentialsManagerException.Code.NO_NETWORK
else -> CredentialsManagerException.Code.API_ERROR
}
callback.onFailure(
CredentialsManagerException(
CredentialsManagerException.Code.RENEW_FAILED,
exception,
error
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public class CredentialsManagerException :
BIOMETRIC_ERROR_UNABLE_TO_PROCESS,
BIOMETRICS_INVALID_USER,
BIOMETRIC_AUTHENTICATION_FAILED,
NO_NETWORK,
API_ERROR
}

private var code: Code?
Expand Down Expand Up @@ -135,6 +137,12 @@ public class CredentialsManagerException :
public val BIOMETRICS_INVALID_USER: CredentialsManagerException =
CredentialsManagerException(Code.BIOMETRICS_INVALID_USER)

//Exceptions thrown when making api calls for access token renewal
public val NO_NETWORK: CredentialsManagerException =
CredentialsManagerException(Code.NO_NETWORK)
public val API_ERROR: CredentialsManagerException =
CredentialsManagerException(Code.API_ERROR)


private fun getMessage(code: Code): String {
return when (code) {
Expand Down Expand Up @@ -177,6 +185,8 @@ public class CredentialsManagerException :
Code.BIOMETRIC_ERROR_UNABLE_TO_PROCESS -> "Failed to authenticate because the sensor was unable to process the current image."
Code.BIOMETRICS_INVALID_USER -> "The user didn't pass the authentication challenge."
Code.BIOMETRIC_AUTHENTICATION_FAILED -> "Biometric authentication failed."
Code.NO_NETWORK -> "Failed to execute the network request."
Code.API_ERROR -> "An error occurred while processing the request."
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.fragment.app.FragmentActivity
import com.auth0.android.Auth0
import com.auth0.android.Auth0Exception
import com.auth0.android.authentication.AuthenticationAPIClient
import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.callback.Callback
import com.auth0.android.request.internal.GsonProvider
import com.auth0.android.result.Credentials
Expand Down Expand Up @@ -585,10 +585,16 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
fresh.expiresAt,
fresh.scope
)
} catch (error: Auth0Exception) {
} catch (error: AuthenticationException) {
val exception = when {
error.isRefreshTokenDeleted ||
error.isInvalidRefreshToken -> CredentialsManagerException.Code.RENEW_FAILED
error.isNetworkError -> CredentialsManagerException.Code.NO_NETWORK
else -> CredentialsManagerException.Code.API_ERROR
}
callback.onFailure(
CredentialsManagerException(
CredentialsManagerException.Code.RENEW_FAILED,
exception,
error
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ public open class AuthenticationActivity : Activity() {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(EXTRA_INTENT_LAUNCHED, intentLaunched)
WebAuthProvider.onSaveInstanceState(outState)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
WebAuthProvider.onRestoreInstanceState(savedInstanceState)
intentLaunched = savedInstanceState.getBoolean(EXTRA_INTENT_LAUNCHED, false)
}
}
Expand Down
Loading

0 comments on commit 98166b1

Please sign in to comment.