Skip to content

Commit e1e7033

Browse files
committed
Added comments to api methods
1 parent cb038bf commit e1e7033

File tree

6 files changed

+172
-12
lines changed

6 files changed

+172
-12
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
6767
get() = auth0.getDomainUrl()
6868

6969

70+
/**
71+
* Enable DPoP for this client.
72+
*/
7073
@RequiresApi(Build.VERSION_CODES.M)
71-
override fun enableDPoP(context: Context): AuthenticationAPIClient {
74+
public override fun enableDPoP(context: Context): AuthenticationAPIClient {
7275
DPoPProvider.generateKeyPair(context)
7376
return this
7477
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@ import java.util.Calendar
2121
import javax.security.auth.x500.X500Principal
2222
import javax.security.cert.CertificateException
2323

24-
public class DPoPKeyStore {
24+
/**
25+
* Class to handle all DPoP related keystore operations
26+
*/
27+
internal class DPoPKeyStore {
2528

2629
private val keyStore: KeyStore by lazy {
2730
KeyStore.getInstance(ANDROID_KEYSTORE).apply {
2831
load(null)
2932
}
3033
}
3134

32-
public fun generateKeyPair(context: Context) {
35+
fun generateKeyPair(context: Context) {
3336
try {
3437
val keyPairGenerator = KeyPairGenerator.getInstance(
3538
KeyProperties.KEY_ALGORITHM_EC,
@@ -75,7 +78,7 @@ public class DPoPKeyStore {
7578
}
7679
}
7780

78-
public fun getKeyPair(): Pair<PrivateKey, PublicKey>? {
81+
fun getKeyPair(): Pair<PrivateKey, PublicKey>? {
7982
try {
8083
val privateKey = keyStore.getKey(KEY_ALIAS, null) as PrivateKey
8184
val publicKey = keyStore.getCertificate(KEY_ALIAS)?.publicKey
@@ -89,15 +92,15 @@ public class DPoPKeyStore {
8992
return null
9093
}
9194

92-
public fun hasKeyPair(): Boolean {
95+
fun hasKeyPair(): Boolean {
9396
try {
9497
return keyStore.containsAlias(KEY_ALIAS)
9598
} catch (e: KeyStoreException) {
9699
throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
97100
}
98101
}
99102

100-
public fun deleteKeyPair() {
103+
fun deleteKeyPair() {
101104
try {
102105
keyStore.deleteEntry(KEY_ALIAS)
103106
} catch (e: KeyStoreException) {

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

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ import java.security.SignatureException
1414
import java.security.interfaces.ECPublicKey
1515
import java.util.UUID
1616

17-
public interface SenderConstraining<T> {
18-
19-
public fun enableDPoP(context: Context): T
20-
21-
}
2217

18+
/**
19+
* Data class returning the value that needs to be added to the request for the `Authorization` and `DPoP` headers.
20+
* @param authorizationHeader value for the `Authorization` header key
21+
* @param dpopProof value for the `DPoP header key . This will be generated only for DPoP requests
22+
*/
2323
public data class HeaderData(val authorizationHeader: String, val dpopProof: String?)
2424

25+
26+
/**
27+
* Util class for securing requests with DPoP (Demonstrating Proof of Possession) as described in
28+
* [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449).
29+
*/
2530
public object DPoPProvider {
2631

2732
private const val TAG = "DPoPManager"
@@ -36,6 +41,27 @@ public object DPoPProvider {
3641
public var auth0Nonce: String? = null
3742
private set
3843

44+
/**
45+
* This method constructs a DPoP proof JWT that includes the HTTP method, URL, and an optional access token and nonce.
46+
*
47+
* ```kotlin
48+
*
49+
* try {
50+
* DPoPProvider.generateProof("{url}", "POST")?.let {
51+
* // Add to the URL request header
52+
* }
53+
* } catch (exception: DPoPException) {
54+
* Log.e(TAG, "Error generating DPoP proof: ${exception.stackTraceToString()}")
55+
* }
56+
*
57+
* ```
58+
*
59+
* @param httpUrl The URL of the HTTP request for which the DPoP proof is being generated.
60+
* @param httpMethod The HTTP method (e.g., "GET", "POST") of the request.
61+
* @param accessToken An optional access token to be included in the proof. If provided, it will be hashed and included in the payload.
62+
* @param nonce An optional nonce value to be included in the proof. This can be used to prevent replay attacks.
63+
* @throws DPoPException if there is an error generating the DPoP proof or accessing the key pair.
64+
*/
3965
@Throws(DPoPException::class)
4066
public fun generateProof(
4167
httpUrl: String,
@@ -86,11 +112,44 @@ public object DPoPProvider {
86112
return "$headerEncoded.$payloadEncoded.${signature}"
87113
}
88114

115+
/**
116+
* Method to clear the DPoP key pair from the keystore. It must be called when the user logs out from a session
117+
* to prevent reuse of the key pair in subsequent sessions.
118+
*
119+
* ```kotlin
120+
*
121+
* try {
122+
* DPoPProvider.clearKeyPair()
123+
* } catch (exception: DPoPException) {
124+
* Log.e(TAG,"Error clearing the key pair from the keystore: ${exception.stackTraceToString()}")
125+
* }
126+
*
127+
* ```
128+
* **Note** : It is the developers responsibility to invoke this method to clear the keystore when logging out a session.
129+
* @throws DPoPException if there is an error deleting the key pair.
130+
*/
89131
@Throws(DPoPException::class)
90132
public fun clearKeyPair() {
91133
keyStore.deleteKeyPair()
92134
}
93135

136+
/**
137+
* Method to get the public key in JWK format. This is used to generate the `jwk` field in the DPoP proof header.
138+
*
139+
* ```kotlin
140+
*
141+
* try {
142+
* val publicKeyJWK = DPoPProvider.getPublicKeyJWK()
143+
* Log.d(TAG, "Public Key JWK: $publicKeyJWK")
144+
* } catch (exception: DPoPException) {
145+
* Log.e(TAG,"Error getting public key JWK: ${exception.stackTraceToString()}")
146+
* }
147+
*
148+
* ```
149+
*
150+
* @return The public key in JWK format or null if the key pair is not present.
151+
* @throws DPoPException if there is an error accessing the key pair.
152+
*/
94153
@Throws(DPoPException::class)
95154
public fun getPublicKeyJWK(): String? {
96155
if (!keyStore.hasKeyPair()) {
@@ -108,6 +167,22 @@ public object DPoPProvider {
108167
return createSHA256Hash(jwkJson.toString())
109168
}
110169

170+
/**
171+
* Generates a new key pair for DPoP if it does not already exist. This should be called before making any requests that require DPoP proof.
172+
*
173+
* ```kotlin
174+
*
175+
* try {
176+
* DPoPProvider.generateKeyPair(context)
177+
* } catch (exception: DPoPException) {
178+
* Log.e(TAG,"Error generating key pair: ${exception.stackTraceToString()}")
179+
* }
180+
*
181+
* ```
182+
*
183+
* @param context The application context used to access the keystore.
184+
* @throws DPoPException if there is an error generating the key pair or accessing the keystore.
185+
*/
111186
@Throws(DPoPException::class)
112187
public fun generateKeyPair(context: Context) {
113188
if (keyStore.hasKeyPair()) {
@@ -116,6 +191,37 @@ public object DPoPProvider {
116191
keyStore.generateKeyPair(context)
117192
}
118193

194+
/**
195+
* Generates the header data for a request that requires DPoP proof of possession. The `Authorization` header value is created
196+
* using the access token and token type. The `DPoP` header value contains the generated DPoP proof
197+
*
198+
* ```kotlin
199+
*
200+
* try {
201+
* val headerData = DPoPProvider.getHeaderData(
202+
* "{POST}",
203+
* "{request_url}",
204+
* "{access_token}",
205+
* "{DPoP}",
206+
* "{nonce_value}"
207+
* )
208+
* addHeader("Authorization", headerData.authorizationHeader) //Adding to request header
209+
* headerData.dpopProof?.let {
210+
* addHeader("DPoP", it)
211+
* }
212+
* } catch (exception: DPoPException) {
213+
* Log.e(TAG, "Error generating DPoP proof: ${exception.stackTraceToString()}")
214+
* }
215+
*
216+
* ```
217+
*
218+
* @param httpMethod Method type of the request
219+
* @param httpUrl Url of the request
220+
* @param accessToken Access token to be included in the `Authorization` header
221+
* @param tokenType Either `DPoP` or `Bearer`
222+
* @param nonce Optional nonce value to be used in the proof
223+
* @throws DPoPException if there is an error generating the DPoP proof or accessing the key pair
224+
*/
119225
@Throws(DPoPException::class)
120226
public fun getHeaderData(
121227
httpMethod: String,
@@ -130,11 +236,41 @@ public object DPoPProvider {
130236
return HeaderData(token, proof)
131237
}
132238

239+
/**
240+
* Checks if the given [Response] indicates that a nonce is required for DPoP requests.
241+
* This is typically used to determine if the request needs to be retried with a nonce.
242+
*
243+
* ```kotlin
244+
*
245+
* if (DPoPProvider.isNonceRequiredError(response)) {
246+
* // Handle nonce required error
247+
* }
248+
*
249+
* ```
250+
*
251+
* @param response The HTTP response to check for nonce requirement.
252+
* @return True if the response indicates that a nonce is required, false otherwise.
253+
*/
133254
public fun isNonceRequiredError(response: Response): Boolean {
134255
return (response.code == 400 && response.getErrorBody().errorCode == NONCE_REQUIRED_ERROR) ||
135256
(response.code == 401 && isResourceServerNonceError(response))
136257
}
137258

259+
/**
260+
* Stores the nonce value from the Okhttp3 [Response] headers.
261+
*
262+
* ```kotlin
263+
*
264+
* try {
265+
* DPoPProvider.storeNonce(response)
266+
* } catch (exception: Exception) {
267+
* Log.e(TAG, "Error storing nonce: ${exception.stackTraceToString()}")
268+
* }
269+
*
270+
* ```
271+
*
272+
* @param response The HTTP response containing the nonce header.
273+
*/
138274
public fun storeNonce(response: Response) {
139275
auth0Nonce = response.headers[NONCE_HEADER]
140276
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.auth0.android.dpop
2+
3+
import android.content.Context
4+
5+
/**
6+
* Interface for SenderConstraining
7+
*/
8+
public interface SenderConstraining<T> {
9+
10+
/**
11+
* Enables DPoP for authentication requests.
12+
*/
13+
public fun enableDPoP(context: Context): T
14+
15+
}

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-
override fun enableDPoP(context: Context): WebAuthProvider {
54+
public override fun enableDPoP(context: Context): WebAuthProvider {
5555
DPoPProvider.generateKeyPair(context)
5656
return this
5757
}

auth0/src/main/java/com/auth0/android/request/RetryInterceptor.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import com.auth0.android.dpop.DPoPProvider
44
import okhttp3.Interceptor
55
import okhttp3.Response
66

7+
/**
8+
* Interceptor that retries requests.
9+
*/
710
internal class RetryInterceptor : Interceptor {
811
override fun intercept(chain: Interceptor.Chain): Response {
912
val request = chain.request()

0 commit comments

Comments
 (0)