Skip to content

Commit 75ca5a1

Browse files
committed
Updated the examples.md file
1 parent 8f19da1 commit 75ca5a1

File tree

5 files changed

+133
-5
lines changed

5 files changed

+133
-5
lines changed

EXAMPLES.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [Changing the Return To URL scheme](#changing-the-return-to-url-scheme)
1212
- [Specify a Custom Logout URL](#specify-a-custom-logout-url)
1313
- [Trusted Web Activity](#trusted-web-activity)
14+
- [DPoP [EA]](#dpop-ea)
1415
- [Authentication API](#authentication-api)
1516
- [Login with database connection](#login-with-database-connection)
1617
- [Login using MFA with One Time Password code](#login-using-mfa-with-one-time-password-code)
@@ -21,6 +22,7 @@
2122
- [Get user information](#get-user-information)
2223
- [Custom Token Exchange](#custom-token-exchange)
2324
- [Native to Web SSO login [EA]](#native-to-web-sso-login-ea)
25+
- [DPoP [EA]](#dpop-ea-1)
2426
- [My Account API](#my-account-api)
2527
- [Enroll a new passkey](#enroll-a-new-passkey)
2628
- [Credentials Manager](#credentials-manager)
@@ -208,6 +210,76 @@ WebAuthProvider.login(account)
208210
.await(this)
209211
```
210212

213+
## DPoP [EA]
214+
215+
> [!NOTE]
216+
> This feature is currently available in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access). Please reach out to Auth0 support to get it enabled for your tenant.
217+
218+
[DPoP](https://www.rfc-editor.org/rfc/rfc9449.html) (Demonstrating Proof of Posession) is an application-level mechanism for sender-constraining OAuth 2.0 access and refresh tokens by proving that the app is in possession of a certain private key. You can enable it by calling the `useDPoP(context:Context)` method.
219+
220+
```kotlin
221+
WebAuthProvider
222+
.useDPoP(requireContext())
223+
.login(account)
224+
.start(requireContext(), object : Callback<Credentials, AuthenticationException> {
225+
override fun onSuccess(result: Credentials) {
226+
println("Credentials $result")
227+
}
228+
override fun onFailure(error: AuthenticationException) {
229+
print("Error $error")
230+
}
231+
})
232+
```
233+
234+
> [!IMPORTANT]
235+
> DPoP will only be used for new user sessions created after enabling it. DPoP **will not** be applied to any requests involving existing access and refresh tokens (such as exchanging the refresh token for new credentials).
236+
>
237+
> This means that, after you've enabled it in your app, DPoP will only take effect when users log in again. It's up to you to decide how to roll out this change to your users. For example, you might require users to log in again the next time they open your app. You'll need to implement the logic to handle this transition based on your app's requirements.
238+
239+
When making requests to your own APIs, use the `DPoP.getHeaderData()` method to get the `Authorization` and `DPoP` header values to be used. The `Authorization` header value is generated using the access token and token type, while the `DPoP` header value is the generated DPoP proof.
240+
241+
```kotlin
242+
val url ="https://example.com/api/endpoint"
243+
val httpMethod = "GET"
244+
val headerData = DPoPProvider.getHeaderData(
245+
httpMethod, url,
246+
accessToken, tokenType
247+
)
248+
httpRequest.apply{
249+
addHeader("Authorization", headerData.authorizationHeader)
250+
headerData.dpopProof?.let {
251+
addHeader("DPoP", it)
252+
}
253+
}
254+
```
255+
If your API is issuing DPoP nonce's to prevent replay attacks, you can pass the nonce value to the `getHeaderData()` method to include it in the DPoP proof. Use the `DPoPProvider.isNonceRequiredError(response: Response)` method to check if a particular API response failed because a nonce is required.
256+
257+
```kotlin
258+
if (DPoPProvider.isNonceRequiredError(response)) {
259+
val nonce = response.headers["DPoP-Nonce"]
260+
val dpopProof = DPoPProvider.generateProof(
261+
url, httpMethod, accessToken, nonce
262+
)
263+
// Retry the request with the new proof
264+
}
265+
```
266+
267+
On logout, you should call `DPoPProvider.clearKeyPair()` to delete the user's key pair from the Keychain.
268+
269+
```kotlin
270+
WebAuthProvider.logout(account)
271+
.start(requireContext(), object : Callback<Void?, AuthenticationException> {
272+
override fun onSuccess(result: Void?) {
273+
DPoPProvider.clearKeyPair()
274+
}
275+
override fun onFailure(error: AuthenticationException) {
276+
}
277+
278+
})
279+
```
280+
> [!NOTE]
281+
> DPoP is supported only on Android version 6.0 (API level 23) and above. Trying to use DPoP in any older versions will result in an exception.
282+
211283
## Authentication API
212284

213285
The client provides methods to authenticate the user against the Auth0 server.
@@ -651,6 +723,62 @@ authentication
651723
```
652724
</details>
653725

726+
## DPoP [EA]
727+
728+
> [!NOTE]
729+
> This feature is currently available in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access). Please reach out to Auth0 support to get it enabled for your tenant.
730+
731+
[DPoP](https://www.rfc-editor.org/rfc/rfc9449.html) (Demonstrating Proof of Posession) is an application-level mechanism for sender-constraining OAuth 2.0 access and refresh tokens by proving that the app is in possession of a certain private key. You can enable it by calling the `useDPoP(context: Context)` method. This ensures that DPoP proofs are generated for requests made through the AuthenticationAPI client.
732+
733+
```kotlin
734+
val client = AuthenticationAPIClient(account).useDPoP(context)
735+
```
736+
737+
[!IMPORTANT]
738+
> DPoP will only be used for new user sessions created after enabling it. DPoP **will not** be applied to any requests involving existing access and refresh tokens (such as exchanging the refresh token for new credentials).
739+
>
740+
> This means that, after you've enabled it in your app, DPoP will only take effect when users log in again. It's up to you to decide how to roll out this change to your users. For example, you might require users to log in again the next time they open your app. You'll need to implement the logic to handle this transition based on your app's requirements.
741+
742+
When making requests to your own APIs, use the `DPoP.getHeaderData()` method to get the `Authorization` and `DPoP` header values to be used. The `Authorization` header value is generated using the access token and token type, while the `DPoP` header value is the generated DPoP proof.
743+
744+
```kotlin
745+
val url ="https://example.com/api/endpoint"
746+
val httpMethod = "GET"
747+
val headerData = DPoPProvider.getHeaderData(
748+
httpMethod, url,
749+
accessToken, tokenType
750+
)
751+
httpRequest.apply{
752+
addHeader("Authorization", headerData.authorizationHeader)
753+
headerData.dpopProof?.let {
754+
addHeader("DPoP", it)
755+
}
756+
}
757+
```
758+
If your API is issuing DPoP nonce's to prevent replay attacks, you can pass the nonce value to the `getHeaderData()` method to include it in the DPoP proof. Use the `DPoPProvider.isNonceRequiredError(response: Response)` method to check if a particular API response failed because a nonce is required.
759+
760+
```kotlin
761+
if (DPoPProvider.isNonceRequiredError(response)) {
762+
val nonce = response.headers["DPoP-Nonce"]
763+
val dpopProof = DPoPProvider.generateProof(
764+
url, httpMethod, accessToken, nonce
765+
)
766+
// Retry the request with the new proof
767+
}
768+
```
769+
770+
On logout, you should call `DPoPProvider.clearKeyPair()` to delete the user's key pair from the Keychain.
771+
772+
```kotlin
773+
774+
DPoPProvider.clearKeyPair()
775+
776+
```
777+
778+
> [!NOTE]
779+
> DPoP is supported only on Android version 6.0 (API level 23) and above. Trying to use DPoP in any older versions will result in an exception.
780+
781+
654782

655783
## My Account API
656784

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
7171
* Enable DPoP for this client.
7272
*/
7373
@RequiresApi(Build.VERSION_CODES.M)
74-
public override fun enableDPoP(context: Context): AuthenticationAPIClient {
74+
public override fun useDPoP(context: Context): AuthenticationAPIClient {
7575
DPoPProvider.generateKeyPair(context)
7676
return this
7777
}

auth0/src/main/java/com/auth0/android/dpop/SenderConstraining.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ public interface SenderConstraining<T> {
1010
/**
1111
* Enables DPoP for authentication requests.
1212
*/
13-
public fun enableDPoP(context: Context): T
13+
public fun useDPoP(context: Context): T
1414

1515
}

auth0/src/main/java/com/auth0/android/provider/WebAuthProvider.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public object WebAuthProvider : SenderConstraining<WebAuthProvider> {
5151
}
5252

5353
@RequiresApi(Build.VERSION_CODES.M)
54-
public override fun enableDPoP(context: Context): WebAuthProvider {
54+
public override fun useDPoP(context: Context): WebAuthProvider {
5555
DPoPProvider.generateKeyPair(context)
5656
return this
5757
}

auth0/src/test/java/com/auth0/android/provider/WebAuthProviderTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ public class WebAuthProviderTest {
325325
public fun enablingDPoPWillGenerateNEwKEyPairIfOneDoesNotExist() {
326326
`when`(mockKeyStore.hasKeyPair()).thenReturn(false)
327327
val context: Context = mock()
328-
WebAuthProvider.enableDPoP(context)
328+
WebAuthProvider.useDPoP(context)
329329
login(account)
330330
.start(activity, callback)
331331
verify(mockKeyStore).generateKeyPair(context)
@@ -352,7 +352,7 @@ public class WebAuthProviderTest {
352352
`when`(mockKeyStore.hasKeyPair()).thenReturn(true)
353353
`when`(mockKeyStore.getKeyPair()).thenReturn(Pair(mock(), FakeECPublicKey()))
354354

355-
WebAuthProvider.enableDPoP(mock())
355+
WebAuthProvider.useDPoP(mock())
356356
login(account)
357357
.start(activity, callback)
358358
verify(activity).startActivity(intentCaptor.capture())

0 commit comments

Comments
 (0)