react-native-dpop 0.4.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,16 +35,17 @@ cd ios && pod install
35
35
  ```ts
36
36
  import { DPoP } from 'react-native-dpop';
37
37
 
38
- const dpop = await DPoP.generateProof({
38
+ const dPoP = await DPoP.generateProof({
39
39
  htu: 'https://api.example.com/token',
40
40
  htm: 'POST',
41
41
  accessToken: 'ACCESS_TOKEN',
42
42
  nonce: 'SERVER_NONCE',
43
+ requireHardwareBacked: true,
43
44
  });
44
45
 
45
- const proof = dpop.proof;
46
- const thumbprint = await dpop.calculateThumbprint();
47
- const publicJwk = await dpop.getPublicKey('JWK');
46
+ const proof = dPoP.proof;
47
+ const thumbprint = await dPoP.getPublicKeyThumbprint();
48
+ const publicJwk = await dPoP.getPublicKey('JWK');
48
49
  const keyInfo = await DPoP.getKeyInfo();
49
50
  ```
50
51
 
@@ -53,6 +54,7 @@ const keyInfo = await DPoP.getKeyInfo();
53
54
  ### Static methods
54
55
 
55
56
  - `DPoP.generateProof(input): Promise<DPoP>`
57
+ - `DPoP.buildDPoPHeaders(input): Promise<DPoPHeaders>`
56
58
  - `DPoP.assertHardwareBacked(alias?): Promise<void>`
57
59
  - `DPoP.deleteKeyPair(alias?): Promise<void>`
58
60
  - `DPoP.getKeyInfo(alias?): Promise<DPoPKeyInfo>`
@@ -64,14 +66,32 @@ const keyInfo = await DPoP.getKeyInfo();
64
66
  - `proof: string`
65
67
  - `proofContext: DPoPProofContext`
66
68
  - `alias?: string`
67
- - `calculateThumbprint(): Promise<string>`
68
69
  - `getPublicKey(format): Promise<PublicJwk | string>`
69
- - `signWithDpopPrivateKey(payload): Promise<string>`
70
+ - `getPublicKeyThumbprint(): Promise<string>`
71
+ - `signWithDPoPPrivateKey(payload): Promise<string>`
70
72
  - `isBoundToAlias(alias?): Promise<boolean>`
71
73
 
74
+ ### `signWithDPoPPrivateKey()`
75
+
76
+ `signWithDPoPPrivateKey()` reuses the same private key pair managed by the DPoP alias. It does not create or use a separate signing key.
77
+
78
+ This means:
79
+
80
+ - the signature is produced with the same key material used for DPoP proofs
81
+ - the active alias determines which private key is used
82
+ - if the alias points to a hardware-backed key, the same hardware-backed key is reused
83
+ - if the alias points to a fallback software-backed key, the same fallback key is reused
84
+
85
+ Recommended usage:
86
+
87
+ - use this only when you intentionally want to sign arbitrary payloads with the same DPoP key
88
+ - avoid treating it as a general-purpose application signing API
89
+ - if you need a different trust boundary or lifecycle, use a different alias or a different key management flow
90
+
72
91
  ### Main types
73
92
 
74
93
  - `GenerateProofInput`
94
+ - `DPoPHeaders`
75
95
  - `DPoPProofContext`
76
96
  - `DPoPKeyInfo`
77
97
  - `PublicJwk`
@@ -130,12 +150,32 @@ type DPoPKeyInfo = {
130
150
  - Fallback reasons are sanitized enums rather than raw native errors
131
151
  - On iOS Simulator, `secureEnclaveFallbackReason` is expected to be `UNAVAILABLE`
132
152
 
153
+ ## `buildDPoPHeaders()`
154
+
155
+ `buildDPoPHeaders()` generates a proof and returns request headers ready to use.
156
+
157
+ ```ts
158
+ const headers = await DPoP.buildDPoPHeaders({
159
+ htu: 'https://api.example.com/token',
160
+ htm: 'POST',
161
+ accessToken: 'ACCESS_TOKEN',
162
+ });
163
+
164
+ // {
165
+ // DPoP: '<proof>',
166
+ // Authorization: 'DPoP ACCESS_TOKEN',
167
+ // }
168
+ ```
169
+
170
+ If `accessToken` is omitted, only the `DPoP` header is returned.
171
+
133
172
  ## Notes
134
173
 
135
174
  - Default alias: `react-native-dpop`
136
175
  - `htm` is normalized to uppercase
137
176
  - `ath` is derived from `accessToken` when provided
138
177
  - `jti` and `iat` are auto-generated when omitted
178
+ - `requireHardwareBacked` forces proof generation to fail instead of silently persisting a software-backed fallback key
139
179
  - For React Native 0.75 on Android, the library ensures `iat` is sent as a number to avoid an older bridge nullability issue with `Double`
140
180
 
141
181
  ## Example apps
@@ -113,6 +113,8 @@ internal class DPoPKeyStore(private val context: Context) {
113
113
  val keyPair = getKeyPair(alias)
114
114
  val keyFactory = KeyFactory.getInstance(keyPair.privateKey.algorithm, KEYSTORE_PROVIDER)
115
115
  val keyInfo = keyFactory.getKeySpec(keyPair.privateKey, KeyInfo::class.java)
116
+ val strongBoxAvailable = isStrongBoxEnabled()
117
+ val strongBoxBacked = strongBoxAvailable && readStrongBoxBacked(keyInfo)
116
118
 
117
119
  return KeyStoreKeyInfo(
118
120
  alias = alias,
@@ -120,9 +122,9 @@ internal class DPoPKeyStore(private val context: Context) {
120
122
  curve = "P-256",
121
123
  insideSecureHardware = keyInfo.isInsideSecureHardware,
122
124
  securityLevel = readSecurityLevel(keyInfo),
123
- securityLevelName = readSecurityLevelName(keyInfo),
124
- strongBoxAvailable = isStrongBoxEnabled(),
125
- strongBoxBacked = readStrongBoxBacked(keyInfo)
125
+ securityLevelName = readSecurityLevelName(keyInfo, strongBoxBacked),
126
+ strongBoxAvailable = strongBoxAvailable,
127
+ strongBoxBacked = strongBoxBacked
126
128
  )
127
129
  }
128
130
 
@@ -174,8 +176,7 @@ internal class DPoPKeyStore(private val context: Context) {
174
176
  }
175
177
  }
176
178
 
177
- private fun readSecurityLevelName(keyInfo: KeyInfo): String {
178
- val strongBoxBacked = readStrongBoxBacked(keyInfo)
179
+ private fun readSecurityLevelName(keyInfo: KeyInfo, strongBoxBacked: Boolean): String {
179
180
  val securityLevel = readSecurityLevel(keyInfo)
180
181
 
181
182
  return when (securityLevel) {
@@ -16,12 +16,29 @@ class DPoPModule(reactContext: ReactApplicationContext) :
16
16
  private const val DEFAULT_ALIAS = "react-native-dpop"
17
17
  const val NAME = NativeReactNativeDPoPSpec.NAME
18
18
  private const val UNKNOWN_STRONGBOX_FALLBACK_REASON = "UNKNOWN"
19
+ private val RESERVED_DPOP_CLAIMS = setOf("ath", "htm", "htu", "iat", "jti", "nonce")
19
20
  }
20
21
 
21
22
  private fun resolveAlias(alias: String?): String {
22
23
  return alias ?: DEFAULT_ALIAS
23
24
  }
24
25
 
26
+ private fun ensureKeyPair(alias: String, requireHardwareBacked: Boolean): Unit {
27
+ var generatedInThisCall = false
28
+
29
+ if (!keyStore.hasKeyPair(alias)) {
30
+ keyStore.generateKeyPair(alias)
31
+ generatedInThisCall = true
32
+ }
33
+
34
+ if (requireHardwareBacked && !keyStore.isHardwareBacked(alias)) {
35
+ if (generatedInThisCall) {
36
+ keyStore.deleteKeyPair(alias)
37
+ }
38
+ throw IllegalStateException("Hardware-backed key required for alias: $alias")
39
+ }
40
+ }
41
+
25
42
  private fun resolveStrongBoxFallbackReason(
26
43
  strongBoxAvailable: Boolean,
27
44
  strongBoxBacked: Boolean,
@@ -57,27 +74,6 @@ class DPoPModule(reactContext: ReactApplicationContext) :
57
74
  }
58
75
  }
59
76
 
60
- override fun calculateThumbprint(alias: String?, promise: Promise) {
61
- try {
62
- val effectiveAlias = resolveAlias(alias)
63
- if (!keyStore.hasKeyPair(effectiveAlias)) {
64
- keyStore.generateKeyPair(effectiveAlias)
65
- }
66
-
67
- val keyPair = keyStore.getKeyPair(effectiveAlias)
68
- val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
69
- val thumbprint = DPoPUtils.calculateThumbprint(
70
- kty = "EC",
71
- crv = "P-256",
72
- x = coordinates.first,
73
- y = coordinates.second
74
- )
75
- promise.resolve(thumbprint)
76
- } catch (e: Exception) {
77
- promise.reject("ERR_DPOP_CALCULATE_THUMBPRINT", e.message, e)
78
- }
79
- }
80
-
81
77
  override fun deleteKeyPair(alias: String?, promise: Promise) {
82
78
  try {
83
79
  val effectiveAlias = resolveAlias(alias)
@@ -205,6 +201,27 @@ class DPoPModule(reactContext: ReactApplicationContext) :
205
201
  }
206
202
  }
207
203
 
204
+ override fun getPublicKeyThumbprint(alias: String?, promise: Promise) {
205
+ try {
206
+ val effectiveAlias = resolveAlias(alias)
207
+ if (!keyStore.hasKeyPair(effectiveAlias)) {
208
+ keyStore.generateKeyPair(effectiveAlias)
209
+ }
210
+
211
+ val keyPair = keyStore.getKeyPair(effectiveAlias)
212
+ val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
213
+ val thumbprint = DPoPUtils.getPublicKeyThumbprint(
214
+ kty = "EC",
215
+ crv = "P-256",
216
+ x = coordinates.first,
217
+ y = coordinates.second
218
+ )
219
+ promise.resolve(thumbprint)
220
+ } catch (e: Exception) {
221
+ promise.reject("ERR_DPOP_CALCULATE_THUMBPRINT", e.message, e)
222
+ }
223
+ }
224
+
208
225
  override fun hasKeyPair(alias: String?, promise: Promise) {
209
226
  try {
210
227
  val effectiveAlias = resolveAlias(alias)
@@ -238,7 +255,7 @@ class DPoPModule(reactContext: ReactApplicationContext) :
238
255
  }
239
256
  }
240
257
 
241
- override fun signWithDpopPrivateKey(payload: String, alias: String?, promise: Promise) {
258
+ override fun signWithDPoPPrivateKey(payload: String, alias: String?, promise: Promise) {
242
259
  try {
243
260
  val effectiveAlias = resolveAlias(alias)
244
261
  if (!keyStore.hasKeyPair(effectiveAlias)) {
@@ -267,13 +284,12 @@ class DPoPModule(reactContext: ReactApplicationContext) :
267
284
  jti: String?,
268
285
  iat: Double?,
269
286
  alias: String?,
287
+ requireHardwareBacked: Boolean,
270
288
  promise: Promise
271
289
  ) {
272
290
  try {
273
291
  val effectiveAlias = resolveAlias(alias)
274
- if (!keyStore.hasKeyPair(effectiveAlias)) {
275
- keyStore.generateKeyPair(effectiveAlias)
276
- }
292
+ ensureKeyPair(effectiveAlias, requireHardwareBacked)
277
293
 
278
294
  val keyPair = keyStore.getKeyPair(effectiveAlias)
279
295
  val coordinates = DPoPUtils.getPublicCoordinates(keyPair.publicKey)
@@ -313,6 +329,9 @@ class DPoPModule(reactContext: ReactApplicationContext) :
313
329
  val keys = additionalJson.keys()
314
330
  while (keys.hasNext()) {
315
331
  val key = keys.next()
332
+ if (RESERVED_DPOP_CLAIMS.contains(key)) {
333
+ throw IllegalArgumentException("additional must not override reserved DPoP claim: $key")
334
+ }
316
335
  payload.put(key, additionalJson.get(key))
317
336
  }
318
337
  }
@@ -18,12 +18,6 @@ internal object DPoPUtils {
18
18
  return Base64.getUrlEncoder().withoutPadding().encodeToString(input)
19
19
  }
20
20
 
21
- internal fun calculateThumbprint(kty: String, crv: String, x: String, y: String): String {
22
- val canonicalJwk = """{"crv":"$crv","kty":"$kty","x":"$x","y":"$y"}"""
23
- val hash = MessageDigest.getInstance("SHA-256").digest(canonicalJwk.toByteArray(Charsets.UTF_8))
24
- return base64UrlEncode(hash)
25
- }
26
-
27
21
  internal fun derToJose(derSignature: ByteArray, partLength: Int = 32): ByteArray {
28
22
  if (derSignature.isEmpty() || derSignature[0].toInt() != 0x30) {
29
23
  throw IllegalArgumentException("Invalid DER signature format")
@@ -65,6 +59,12 @@ internal object DPoPUtils {
65
59
  return Pair(x, y)
66
60
  }
67
61
 
62
+ internal fun getPublicKeyThumbprint(kty: String, crv: String, x: String, y: String): String {
63
+ val canonicalJwk = """{"crv":"$crv","kty":"$kty","x":"$x","y":"$y"}"""
64
+ val hash = MessageDigest.getInstance("SHA-256").digest(canonicalJwk.toByteArray(Charsets.UTF_8))
65
+ return base64UrlEncode(hash)
66
+ }
67
+
68
68
  internal fun hashAccessToken(accessToken: String): String {
69
69
  val hash = MessageDigest.getInstance("SHA-256").digest(accessToken.toByteArray(Charsets.UTF_8))
70
70
  return base64UrlEncode(hash)
@@ -93,7 +93,7 @@ final class DPoPKeyStore {
93
93
  }
94
94
 
95
95
  func isHardwareBacked(alias: String) -> Bool {
96
- secureEnclave.isHardwareBacked(alias: alias)
96
+ secureEnclaveAvailable && secureEnclave.isHardwareBacked(alias: alias)
97
97
  }
98
98
 
99
99
  func isSecureEnclaveAvailable() -> Bool {
@@ -7,6 +7,7 @@ final class DPoPModule {
7
7
 
8
8
  private let keyStore = DPoPKeyStore()
9
9
  private let defaultAlias = "react-native-dpop"
10
+ private let reservedDPoPClaims = Set(["ath", "htm", "htu", "iat", "jti", "nonce"])
10
11
  private let unknownSecureEnclaveFallbackReason = "UNKNOWN"
11
12
  private let unavailableSecureEnclaveFallbackReason = "UNAVAILABLE"
12
13
 
@@ -19,6 +20,24 @@ final class DPoPModule {
19
20
  return alias
20
21
  }
21
22
 
23
+ func ensureKeyPair(alias: String, requireHardwareBacked: Bool) throws {
24
+ var generatedInThisCall = false
25
+
26
+ if !keyStore.hasKeyPair(alias: alias) {
27
+ try keyStore.generateKeyPair(alias: alias)
28
+ generatedInThisCall = true
29
+ }
30
+
31
+ let isHardwareBacked = keyStore.isHardwareBacked(alias: alias)
32
+
33
+ if requireHardwareBacked && !isHardwareBacked {
34
+ if generatedInThisCall {
35
+ try? keyStore.deleteKeyPair(alias: alias)
36
+ }
37
+ throw DPoPError.notHardwareBacked(alias: alias)
38
+ }
39
+ }
40
+
22
41
  func assertHardwareBacked(alias: String?) throws {
23
42
  let effectiveAlias = resolveAlias(alias)
24
43
  guard keyStore.hasKeyPair(alias: effectiveAlias) else {
@@ -30,16 +49,6 @@ final class DPoPModule {
30
49
  }
31
50
  }
32
51
 
33
- func calculateThumbprint(alias: String?) throws -> String {
34
- let effectiveAlias = resolveAlias(alias)
35
- if !keyStore.hasKeyPair(alias: effectiveAlias) {
36
- try keyStore.generateKeyPair(alias: effectiveAlias)
37
- }
38
- let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
39
- let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
40
- return DPoPUtils.calculateThumbprint(kty: "EC", crv: "P-256", x: coordinates.x, y: coordinates.y)
41
- }
42
-
43
52
  func deleteKeyPair(alias: String?) throws {
44
53
  try keyStore.deleteKeyPair(alias: resolveAlias(alias))
45
54
  }
@@ -148,6 +157,16 @@ final class DPoPModule {
148
157
  return DPoPUtils.base64UrlEncode(try DPoPUtils.toRawPublicKey(keyPair.publicKey))
149
158
  }
150
159
 
160
+ func getPublicKeyThumbprint(alias: String?) throws -> String {
161
+ let effectiveAlias = resolveAlias(alias)
162
+ if !keyStore.hasKeyPair(alias: effectiveAlias) {
163
+ try keyStore.generateKeyPair(alias: effectiveAlias)
164
+ }
165
+ let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
166
+ let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
167
+ return DPoPUtils.getPublicKeyThumbprint(kty: "EC", crv: "P-256", x: coordinates.x, y: coordinates.y)
168
+ }
169
+
151
170
  func hasKeyPair(alias: String?) -> Bool {
152
171
  keyStore.hasKeyPair(alias: resolveAlias(alias))
153
172
  }
@@ -165,7 +184,7 @@ final class DPoPModule {
165
184
  try keyStore.generateKeyPair(alias: resolveAlias(alias))
166
185
  }
167
186
 
168
- func signWithDpopPrivateKey(payload: String, alias: String?) throws -> String {
187
+ func signWithDPoPPrivateKey(payload: String, alias: String?) throws -> String {
169
188
  let effectiveAlias = resolveAlias(alias)
170
189
  if !keyStore.hasKeyPair(alias: effectiveAlias) {
171
190
  try keyStore.generateKeyPair(alias: effectiveAlias)
@@ -193,12 +212,11 @@ final class DPoPModule {
193
212
  kid: String?,
194
213
  jti: String?,
195
214
  iat: NSNumber?,
196
- alias: String?
215
+ alias: String?,
216
+ requireHardwareBacked: Bool
197
217
  ) throws -> [String: Any] {
198
218
  let effectiveAlias = resolveAlias(alias)
199
- if !keyStore.hasKeyPair(alias: effectiveAlias) {
200
- try keyStore.generateKeyPair(alias: effectiveAlias)
201
- }
219
+ try ensureKeyPair(alias: effectiveAlias, requireHardwareBacked: requireHardwareBacked)
202
220
  let keyPair = try keyStore.getKeyPair(alias: effectiveAlias)
203
221
  let coordinates = try DPoPUtils.getPublicCoordinates(fromRawPublicKey: try DPoPUtils.toRawPublicKey(keyPair.publicKey))
204
222
 
@@ -239,6 +257,13 @@ final class DPoPModule {
239
257
 
240
258
  if let additional {
241
259
  for (key, value) in additional {
260
+ if reservedDPoPClaims.contains(key) {
261
+ throw NSError(
262
+ domain: "ReactNativeDPoP",
263
+ code: 0,
264
+ userInfo: [NSLocalizedDescriptionKey: "additional must not override reserved DPoP claim: \(key)"]
265
+ )
266
+ }
242
267
  payload[key] = value
243
268
  }
244
269
  }
@@ -296,14 +321,6 @@ final class DPoPModule {
296
321
  }
297
322
  }
298
323
 
299
- func calculateThumbprint(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
300
- do {
301
- resolve(try DPoPModule.shared.calculateThumbprint(alias: alias))
302
- } catch {
303
- reject("ERR_DPOP_CALCULATE_THUMBPRINT", error.localizedDescription, error)
304
- }
305
- }
306
-
307
324
  func deleteKeyPair(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
308
325
  do {
309
326
  try DPoPModule.shared.deleteKeyPair(alias: alias)
@@ -341,6 +358,14 @@ final class DPoPModule {
341
358
  }
342
359
  }
343
360
 
361
+ func getPublicKeyThumbprint(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
362
+ do {
363
+ resolve(try DPoPModule.shared.getPublicKeyThumbprint(alias: alias))
364
+ } catch {
365
+ reject("ERR_DPOP_CALCULATE_THUMBPRINT", error.localizedDescription, error)
366
+ }
367
+ }
368
+
344
369
  func hasKeyPair(_ alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
345
370
  resolve(DPoPModule.shared.hasKeyPair(alias: alias))
346
371
  }
@@ -362,9 +387,9 @@ final class DPoPModule {
362
387
  }
363
388
  }
364
389
 
365
- func signWithDpopPrivateKey(_ payload: String, alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
390
+ func signWithDPoPPrivateKey(_ payload: String, alias: String?, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
366
391
  do {
367
- resolve(try DPoPModule.shared.signWithDpopPrivateKey(payload: payload, alias: alias))
392
+ resolve(try DPoPModule.shared.signWithDPoPPrivateKey(payload: payload, alias: alias))
368
393
  } catch {
369
394
  reject("ERR_DPOP_SIGN_WITH_PRIVATE_KEY", error.localizedDescription, error)
370
395
  }
@@ -380,6 +405,7 @@ final class DPoPModule {
380
405
  jti: String?,
381
406
  iat: Any?,
382
407
  alias: String?,
408
+ requireHardwareBacked: Bool,
383
409
  resolve: @escaping RCTPromiseResolveBlock,
384
410
  reject: @escaping RCTPromiseRejectBlock
385
411
  ) {
@@ -401,7 +427,8 @@ final class DPoPModule {
401
427
  kid: kid,
402
428
  jti: jti,
403
429
  iat: normalizedIat,
404
- alias: alias
430
+ alias: alias,
431
+ requireHardwareBacked: requireHardwareBacked
405
432
  )
406
433
  )
407
434
  } catch {
@@ -21,10 +21,6 @@ RCT_EXTERN_METHOD(assertHardwareBacked:(NSString * _Nullable)alias
21
21
  resolve:(RCTPromiseResolveBlock)resolve
22
22
  reject:(RCTPromiseRejectBlock)reject)
23
23
 
24
- RCT_EXTERN_METHOD(calculateThumbprint:(NSString * _Nullable)alias
25
- resolve:(RCTPromiseResolveBlock)resolve
26
- reject:(RCTPromiseRejectBlock)reject)
27
-
28
24
  RCT_EXTERN_METHOD(deleteKeyPair:(NSString * _Nullable)alias
29
25
  resolve:(RCTPromiseResolveBlock)resolve
30
26
  reject:(RCTPromiseRejectBlock)reject)
@@ -45,6 +41,10 @@ RCT_EXTERN_METHOD(getPublicKeyRaw:(NSString * _Nullable)alias
45
41
  resolve:(RCTPromiseResolveBlock)resolve
46
42
  reject:(RCTPromiseRejectBlock)reject)
47
43
 
44
+ RCT_EXTERN_METHOD(getPublicKeyThumbprint:(NSString * _Nullable)alias
45
+ resolve:(RCTPromiseResolveBlock)resolve
46
+ reject:(RCTPromiseRejectBlock)reject)
47
+
48
48
  RCT_EXTERN_METHOD(hasKeyPair:(NSString * _Nullable)alias
49
49
  resolve:(RCTPromiseResolveBlock)resolve
50
50
  reject:(RCTPromiseRejectBlock)reject)
@@ -58,7 +58,7 @@ RCT_EXTERN_METHOD(rotateKeyPair:(NSString * _Nullable)alias
58
58
  resolve:(RCTPromiseResolveBlock)resolve
59
59
  reject:(RCTPromiseRejectBlock)reject)
60
60
 
61
- RCT_EXTERN_METHOD(signWithDpopPrivateKey:(NSString *)payload
61
+ RCT_EXTERN_METHOD(signWithDPoPPrivateKey:(NSString *)payload
62
62
  alias:(NSString * _Nullable)alias
63
63
  resolve:(RCTPromiseResolveBlock)resolve
64
64
  reject:(RCTPromiseRejectBlock)reject)
@@ -72,6 +72,7 @@ RCT_EXTERN_METHOD(generateProof:(NSString *)htu
72
72
  jti:(NSString * _Nullable)jti
73
73
  iat:(id _Nullable)iat
74
74
  alias:(NSString * _Nullable)alias
75
+ requireHardwareBacked:(BOOL)requireHardwareBacked
75
76
  resolve:(RCTPromiseResolveBlock)resolve
76
77
  reject:(RCTPromiseRejectBlock)reject)
77
78
 
@@ -28,11 +28,6 @@ enum DPoPUtils {
28
28
  return base64UrlEncode(sha256(data))
29
29
  }
30
30
 
31
- static func calculateThumbprint(kty: String, crv: String, x: String, y: String) -> String {
32
- let canonical = "{\"crv\":\"\(crv)\",\"kty\":\"\(kty)\",\"x\":\"\(x)\",\"y\":\"\(y)\"}"
33
- return base64UrlEncode(sha256(Data(canonical.utf8)))
34
- }
35
-
36
31
  static func jsonData(_ object: Any) throws -> Data {
37
32
  if #available(iOS 11.0, *) {
38
33
  return try JSONSerialization.data(withJSONObject: object, options: [.sortedKeys])
@@ -92,6 +87,11 @@ enum DPoPUtils {
92
87
  return (base64UrlEncode(x), base64UrlEncode(y))
93
88
  }
94
89
 
90
+ static func getPublicKeyThumbprint(kty: String, crv: String, x: String, y: String) -> String {
91
+ let canonical = "{\"crv\":\"\(crv)\",\"kty\":\"\(kty)\",\"x\":\"\(x)\",\"y\":\"\(y)\"}"
92
+ return base64UrlEncode(sha256(Data(canonical.utf8)))
93
+ }
94
+
95
95
  static func toRawPublicKey(_ publicKey: SecKey) throws -> Data {
96
96
  var error: Unmanaged<CFError>?
97
97
  guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  import { NativeModules, TurboModuleRegistry } from 'react-native';
4
- const nativeDpopModule =
4
+ const nativeDPoPModule =
5
5
  // eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
6
6
  TurboModuleRegistry.get('ReactNativeDPoP') ?? NativeModules['ReactNativeDPoP'];
7
- export default nativeDpopModule;
7
+ export default nativeDPoPModule;
8
8
  //# sourceMappingURL=NativeReactNativeDPoP.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeModules","TurboModuleRegistry","nativeDpopModule","get"],"sourceRoot":"../../src","sources":["NativeReactNativeDPoP.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;AA4BjE,MAAMC,gBAAgB;AACpB;AACAD,mBAAmB,CAACE,GAAG,CAAO,iBAAiB,CAAC,IAAKH,aAAa,CAAC,iBAAiB,CAAsB;AAE5G,eAAeE,gBAAgB","ignoreList":[]}
1
+ {"version":3,"names":["NativeModules","TurboModuleRegistry","nativeDPoPModule","get"],"sourceRoot":"../../src","sources":["NativeReactNativeDPoP.ts"],"mappings":";;AACA,SAASA,aAAa,EAAEC,mBAAmB,QAAQ,cAAc;AA6BjE,MAAMC,gBAAgB;AACpB;AACAD,mBAAmB,CAACE,GAAG,CAAO,iBAAiB,CAAC,IAAKH,aAAa,CAAC,iBAAiB,CAAsB;AAE5G,eAAeE,gBAAgB","ignoreList":[]}
@@ -7,36 +7,27 @@ export class DPoP {
7
7
  this.proofContext = proofContext;
8
8
  this.alias = alias;
9
9
  }
10
- async calculateThumbprint() {
11
- return NativeReactNativeDPoP.calculateThumbprint(this.alias ?? null);
12
- }
13
- async getPublicKey(format) {
14
- if (format === 'DER') {
15
- return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
16
- }
17
- if (format === 'RAW') {
18
- return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
19
- }
20
- return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null);
10
+ static async assertHardwareBacked(alias) {
11
+ await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
21
12
  }
22
- async signWithDpopPrivateKey(payload) {
23
- return NativeReactNativeDPoP.signWithDpopPrivateKey(payload, this.alias ?? null);
13
+ static async buildDPoPHeaders(input) {
14
+ const dPoP = await DPoP.generateProof(input);
15
+ return {
16
+ DPoP: dPoP.proof,
17
+ ...(input.accessToken ? {
18
+ Authorization: `DPoP ${input.accessToken}`
19
+ } : {})
20
+ };
24
21
  }
25
- async isBoundToAlias(alias) {
26
- return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
22
+ static async deleteKeyPair(alias) {
23
+ await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
27
24
  }
28
25
  static async generateProof(input) {
29
26
  const result = await NativeReactNativeDPoP.generateProof(input.htu, input.htm, input.nonce ?? null, input.accessToken ?? null, input.additional ?? null, input.kid ?? null, input.jti ?? null,
30
27
  // RN 0.75 Android bridge can crash when a nullable Double arrives as null.
31
- input.iat ?? Math.floor(Date.now() / 1000), input.alias ?? null);
28
+ input.iat ?? Math.floor(Date.now() / 1000), input.alias ?? null, input.requireHardwareBacked ?? false);
32
29
  return new DPoP(result.proof, result.proofContext, input.alias);
33
30
  }
34
- static async assertHardwareBacked(alias) {
35
- await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
36
- }
37
- static async deleteKeyPair(alias) {
38
- await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
39
- }
40
31
  static async getKeyInfo(alias) {
41
32
  return NativeReactNativeDPoP.getKeyInfo(alias ?? null);
42
33
  }
@@ -46,5 +37,23 @@ export class DPoP {
46
37
  static async rotateKeyPair(alias) {
47
38
  await NativeReactNativeDPoP.rotateKeyPair(alias ?? null);
48
39
  }
40
+ async getPublicKey(format) {
41
+ if (format === 'DER') {
42
+ return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
43
+ }
44
+ if (format === 'RAW') {
45
+ return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
46
+ }
47
+ return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null);
48
+ }
49
+ async getPublicKeyThumbprint() {
50
+ return NativeReactNativeDPoP.getPublicKeyThumbprint(this.alias ?? null);
51
+ }
52
+ async isBoundToAlias(alias) {
53
+ return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
54
+ }
55
+ async signWithDPoPPrivateKey(payload) {
56
+ return NativeReactNativeDPoP.signWithDPoPPrivateKey(payload, this.alias ?? null);
57
+ }
49
58
  }
50
59
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","calculateThumbprint","getPublicKey","format","getPublicKeyDer","getPublicKeyRaw","getPublicKeyJwk","signWithDpopPrivateKey","payload","isBoundToAlias","generateProof","input","result","htu","htm","nonce","accessToken","additional","kid","jti","iat","Math","floor","Date","now","assertHardwareBacked","deleteKeyPair","getKeyInfo","hasKeyPair","rotateKeyPair"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,qBAAqB,MAAM,4BAAyB;AAqE3D,OAAO,MAAMC,IAAI,CAAC;EAKRC,WAAWA,CAACC,KAAa,EAAEC,YAA8B,EAAEC,KAAc,EAAE;IACjF,IAAI,CAACF,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACC,YAAY,GAAGA,YAAY;IAChC,IAAI,CAACC,KAAK,GAAGA,KAAK;EACpB;EAEA,MAAaC,mBAAmBA,CAAA,EAAoB;IAClD,OAAON,qBAAqB,CAACM,mBAAmB,CAAC,IAAI,CAACD,KAAK,IAAI,IAAI,CAAC;EACtE;EAEA,MAAaE,YAAYA,CAACC,MAAuB,EAA+B;IAC9E,IAAIA,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACS,eAAe,CAAC,IAAI,CAACJ,KAAK,IAAI,IAAI,CAAC;IAClE;IACA,IAAIG,MAAM,KAAK,KAAK,EAAE;MACpB,OAAOR,qBAAqB,CAACU,eAAe,CAAC,IAAI,CAACL,KAAK,IAAI,IAAI,CAAC;IAClE;IAEA,OAAOL,qBAAqB,CAACW,eAAe,CAAC,IAAI,CAACN,KAAK,IAAI,IAAI,CAAC;EAClE;EAEA,MAAaO,sBAAsBA,CAACC,OAAe,EAAmB;IACpE,OAAOb,qBAAqB,CAACY,sBAAsB,CAACC,OAAO,EAAE,IAAI,CAACR,KAAK,IAAI,IAAI,CAAC;EAClF;EAEA,MAAaS,cAAcA,CAACT,KAAc,EAAoB;IAC5D,OAAOL,qBAAqB,CAACc,cAAc,CAAC,IAAI,CAACX,KAAK,EAAEE,KAAK,IAAI,IAAI,CAACA,KAAK,IAAI,IAAI,CAAC;EACtF;EAEA,aAAoBU,aAAaA,CAACC,KAAyB,EAAiB;IAC1E,MAAMC,MAAM,GAAI,MAAMjB,qBAAqB,CAACe,aAAa,CACvDC,KAAK,CAACE,GAAG,EACTF,KAAK,CAACG,GAAG,EACTH,KAAK,CAACI,KAAK,IAAI,IAAI,EACnBJ,KAAK,CAACK,WAAW,IAAI,IAAI,EACzBL,KAAK,CAACM,UAAU,IAAI,IAAI,EACxBN,KAAK,CAACO,GAAG,IAAI,IAAI,EACjBP,KAAK,CAACQ,GAAG,IAAI,IAAI;IACjB;IACAR,KAAK,CAACS,GAAG,IAAIC,IAAI,CAACC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1Cb,KAAK,CAACX,KAAK,IAAI,IACjB,CAAyB;IAEzB,OAAO,IAAIJ,IAAI,CAACgB,MAAM,CAACd,KAAK,EAAEc,MAAM,CAACb,YAAY,EAAEY,KAAK,CAACX,KAAK,CAAC;EACjE;EAEA,aAAoByB,oBAAoBA,CAACzB,KAAc,EAAiB;IACtE,MAAML,qBAAqB,CAAC8B,oBAAoB,CAACzB,KAAK,IAAI,IAAI,CAAC;EACjE;EAEA,aAAoB0B,aAAaA,CAAC1B,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAAC+B,aAAa,CAAC1B,KAAK,IAAI,IAAI,CAAC;EAC1D;EAEA,aAAoB2B,UAAUA,CAAC3B,KAAc,EAAwB;IACnE,OAAOL,qBAAqB,CAACgC,UAAU,CAAC3B,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoB4B,UAAUA,CAAC5B,KAAc,EAAoB;IAC/D,OAAOL,qBAAqB,CAACiC,UAAU,CAAC5B,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoB6B,aAAaA,CAAC7B,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAACkC,aAAa,CAAC7B,KAAK,IAAI,IAAI,CAAC;EAC1D;AACF","ignoreList":[]}
1
+ {"version":3,"names":["NativeReactNativeDPoP","DPoP","constructor","proof","proofContext","alias","assertHardwareBacked","buildDPoPHeaders","input","dPoP","generateProof","accessToken","Authorization","deleteKeyPair","result","htu","htm","nonce","additional","kid","jti","iat","Math","floor","Date","now","requireHardwareBacked","getKeyInfo","hasKeyPair","rotateKeyPair","getPublicKey","format","getPublicKeyDer","getPublicKeyRaw","getPublicKeyJwk","getPublicKeyThumbprint","isBoundToAlias","signWithDPoPPrivateKey","payload"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,qBAAqB,MAAM,4BAAyB;AA2E3D,OAAO,MAAMC,IAAI,CAAC;EAKRC,WAAWA,CAACC,KAAa,EAAEC,YAA8B,EAAEC,KAAc,EAAE;IACjF,IAAI,CAACF,KAAK,GAAGA,KAAK;IAClB,IAAI,CAACC,YAAY,GAAGA,YAAY;IAChC,IAAI,CAACC,KAAK,GAAGA,KAAK;EACpB;EAEA,aAAoBC,oBAAoBA,CAACD,KAAc,EAAiB;IACtE,MAAML,qBAAqB,CAACM,oBAAoB,CAACD,KAAK,IAAI,IAAI,CAAC;EACjE;EAEA,aAAoBE,gBAAgBA,CAACC,KAAyB,EAAwB;IACpF,MAAMC,IAAI,GAAG,MAAMR,IAAI,CAACS,aAAa,CAACF,KAAK,CAAC;IAE5C,OAAO;MACLP,IAAI,EAAEQ,IAAI,CAACN,KAAK;MAChB,IAAIK,KAAK,CAACG,WAAW,GAAG;QAAEC,aAAa,EAAE,QAAQJ,KAAK,CAACG,WAAW;MAAG,CAAC,GAAG,CAAC,CAAC;IAC7E,CAAC;EACH;EAEA,aAAoBE,aAAaA,CAACR,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAACa,aAAa,CAACR,KAAK,IAAI,IAAI,CAAC;EAC1D;EAEA,aAAoBK,aAAaA,CAACF,KAAyB,EAAiB;IAC1E,MAAMM,MAAM,GAAI,MAAMd,qBAAqB,CAACU,aAAa,CACvDF,KAAK,CAACO,GAAG,EACTP,KAAK,CAACQ,GAAG,EACTR,KAAK,CAACS,KAAK,IAAI,IAAI,EACnBT,KAAK,CAACG,WAAW,IAAI,IAAI,EACzBH,KAAK,CAACU,UAAU,IAAI,IAAI,EACxBV,KAAK,CAACW,GAAG,IAAI,IAAI,EACjBX,KAAK,CAACY,GAAG,IAAI,IAAI;IACjB;IACAZ,KAAK,CAACa,GAAG,IAAIC,IAAI,CAACC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAC1CjB,KAAK,CAACH,KAAK,IAAI,IAAI,EACnBG,KAAK,CAACkB,qBAAqB,IAAI,KACjC,CAAyB;IAEzB,OAAO,IAAIzB,IAAI,CAACa,MAAM,CAACX,KAAK,EAAEW,MAAM,CAACV,YAAY,EAAEI,KAAK,CAACH,KAAK,CAAC;EACjE;EAEA,aAAoBsB,UAAUA,CAACtB,KAAc,EAAwB;IACnE,OAAOL,qBAAqB,CAAC2B,UAAU,CAACtB,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoBuB,UAAUA,CAACvB,KAAc,EAAoB;IAC/D,OAAOL,qBAAqB,CAAC4B,UAAU,CAACvB,KAAK,IAAI,IAAI,CAAC;EACxD;EAEA,aAAoBwB,aAAaA,CAACxB,KAAc,EAAiB;IAC/D,MAAML,qBAAqB,CAAC6B,aAAa,CAACxB,KAAK,IAAI,IAAI,CAAC;EAC1D;EAEA,MAAayB,YAAYA,CAACC,MAAuB,EAA+B;IAC9E,IAAIA,MAAM,KAAK,KAAK,EAAE;MACpB,OAAO/B,qBAAqB,CAACgC,eAAe,CAAC,IAAI,CAAC3B,KAAK,IAAI,IAAI,CAAC;IAClE;IACA,IAAI0B,MAAM,KAAK,KAAK,EAAE;MACpB,OAAO/B,qBAAqB,CAACiC,eAAe,CAAC,IAAI,CAAC5B,KAAK,IAAI,IAAI,CAAC;IAClE;IAEA,OAAOL,qBAAqB,CAACkC,eAAe,CAAC,IAAI,CAAC7B,KAAK,IAAI,IAAI,CAAC;EAClE;EAEA,MAAa8B,sBAAsBA,CAAA,EAAoB;IACrD,OAAOnC,qBAAqB,CAACmC,sBAAsB,CAAC,IAAI,CAAC9B,KAAK,IAAI,IAAI,CAAC;EACzE;EAEA,MAAa+B,cAAcA,CAAC/B,KAAc,EAAoB;IAC5D,OAAOL,qBAAqB,CAACoC,cAAc,CAAC,IAAI,CAACjC,KAAK,EAAEE,KAAK,IAAI,IAAI,CAACA,KAAK,IAAI,IAAI,CAAC;EACtF;EAEA,MAAagC,sBAAsBA,CAACC,OAAe,EAAmB;IACpE,OAAOtC,qBAAqB,CAACqC,sBAAsB,CAACC,OAAO,EAAE,IAAI,CAACjC,KAAK,IAAI,IAAI,CAAC;EAClF;AACF","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- export default function DPoPExampleContent(): import("react/jsx-runtime").JSX.Element;
1
+ export default function DPoPExampleContent(): JSX.Element;
2
2
  //# sourceMappingURL=DPoPExampleContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DPoPExampleContent.d.ts","sourceRoot":"","sources":["../../../../examples/shared/DPoPExampleContent.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CA0BzC"}
1
+ {"version":3,"file":"DPoPExampleContent.d.ts","sourceRoot":"","sources":["../../../../examples/shared/DPoPExampleContent.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,kBAAkB,IAAI,GAAG,CAAC,OAAO,CA2BxD"}
@@ -1,2 +1,2 @@
1
- export default function App(): import("react/jsx-runtime").JSX.Element;
1
+ export default function App(): JSX.Element;
2
2
  //# sourceMappingURL=App.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.75/App.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,GAAG,4CAM1B"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.75/App.tsx"],"names":[],"mappings":"AAIA,MAAM,CAAC,OAAO,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAMzC"}
@@ -1,2 +1,2 @@
1
- export default function App(): import("react/jsx-runtime").JSX.Element;
1
+ export default function App(): JSX.Element;
2
2
  //# sourceMappingURL=App.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.83/App.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,GAAG,4CAM1B"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../examples/v0.83/App.tsx"],"names":[],"mappings":"AAKA,MAAM,CAAC,OAAO,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAMzC"}
@@ -2,17 +2,17 @@ import type { TurboModule } from 'react-native';
2
2
  import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
3
3
  export interface Spec extends TurboModule {
4
4
  assertHardwareBacked(alias: string | null): Promise<void>;
5
- calculateThumbprint(alias: string | null): Promise<string>;
6
5
  deleteKeyPair(alias: string | null): Promise<void>;
6
+ generateProof(htu: string, htm: string, nonce: string | null, accessToken: string | null, additional: UnsafeObject | null, kid: string | null, jti: string | null, iat: number | null, alias: string | null, requireHardwareBacked: boolean): Promise<UnsafeObject>;
7
7
  getKeyInfo(alias: string | null): Promise<UnsafeObject>;
8
8
  getPublicKeyDer(alias: string | null): Promise<string>;
9
9
  getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
10
10
  getPublicKeyRaw(alias: string | null): Promise<string>;
11
+ getPublicKeyThumbprint(alias: string | null): Promise<string>;
11
12
  hasKeyPair(alias: string | null): Promise<boolean>;
12
13
  isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
13
14
  rotateKeyPair(alias: string | null): Promise<void>;
14
- signWithDpopPrivateKey(payload: string, alias: string | null): Promise<string>;
15
- generateProof(htu: string, htm: string, nonce: string | null, accessToken: string | null, additional: UnsafeObject | null, kid: string | null, jti: string | null, iat: number | null, alias: string | null): Promise<UnsafeObject>;
15
+ signWithDPoPPrivateKey(payload: string, alias: string | null): Promise<string>;
16
16
  }
17
17
  declare const _default: Spec;
18
18
  export default _default;
@@ -1 +1 @@
1
- {"version":3,"file":"NativeReactNativeDPoP.d.ts","sourceRoot":"","sources":["../../../src/NativeReactNativeDPoP.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAE9E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,aAAa,CACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1B;wBAMkC,IAAI;AAAvC,wBAAwC"}
1
+ {"version":3,"file":"NativeReactNativeDPoP.d.ts","sourceRoot":"","sources":["../../../src/NativeReactNativeDPoP.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2CAA2C,CAAC;AAE9E,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,aAAa,CACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,UAAU,EAAE,YAAY,GAAG,IAAI,EAC/B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,KAAK,EAAE,MAAM,GAAG,IAAI,EACpB,qBAAqB,EAAE,OAAO,GAC7B,OAAO,CAAC,YAAY,CAAC,CAAC;IACzB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACxD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7D,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtE,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAChF;wBAMkC,IAAI;AAAvC,wBAAwC"}
@@ -1,7 +1,7 @@
1
1
  type AdditionalClaims = Record<string, unknown>;
2
2
  export type PublicJwk = {
3
- kty: 'EC';
4
3
  crv: 'P-256';
4
+ kty: 'EC';
5
5
  x: string;
6
6
  y: string;
7
7
  };
@@ -10,64 +10,70 @@ export type SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'P
10
10
  export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
11
11
  export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
12
12
  export type DPoPKeyInfo = {
13
- alias: string;
14
- hasKeyPair: boolean;
15
13
  algorithm?: string;
14
+ alias: string;
16
15
  curve?: string;
17
- insideSecureHardware?: boolean;
18
16
  hardware?: {
19
17
  android?: {
20
- strongBoxAvailable: boolean;
21
- strongBoxBacked: boolean;
22
18
  securityLevel?: number;
23
19
  securityLevelName?: AndroidSecurityLevelName;
20
+ strongBoxAvailable: boolean;
21
+ strongBoxBacked: boolean;
24
22
  strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
25
23
  };
26
24
  ios?: {
27
25
  secureEnclaveAvailable: boolean;
28
26
  secureEnclaveBacked: boolean;
27
+ secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
29
28
  securityLevel?: number | null;
30
29
  securityLevelName?: IOSSecurityLevelName;
31
- secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
32
30
  };
33
31
  };
32
+ hasKeyPair: boolean;
33
+ insideSecureHardware?: boolean;
34
34
  };
35
35
  export type GenerateProofInput = {
36
- htu: string;
37
- htm: string;
38
- nonce?: string;
39
36
  accessToken?: string;
40
37
  additional?: AdditionalClaims;
41
- kid?: string;
42
- jti?: string;
43
- iat?: number;
44
38
  alias?: string;
39
+ htm: string;
40
+ htu: string;
41
+ iat?: number;
42
+ jti?: string;
43
+ kid?: string;
44
+ nonce?: string;
45
+ requireHardwareBacked?: boolean;
46
+ };
47
+ export type DPoPHeaders = {
48
+ Authorization?: string;
49
+ DPoP: string;
45
50
  };
46
51
  export type DPoPProofContext = {
47
- htu: string;
48
- htm: string;
49
- nonce: string | null;
50
- ath: string | null;
51
52
  additional: AdditionalClaims | null;
52
- kid: string | null;
53
- jti: string;
53
+ ath: string | null;
54
+ htm: string;
55
+ htu: string;
54
56
  iat: number;
57
+ jti: string;
58
+ kid: string | null;
59
+ nonce: string | null;
55
60
  };
56
61
  export declare class DPoP {
57
- readonly proof: string;
58
62
  readonly alias: string | undefined;
63
+ readonly proof: string;
59
64
  readonly proofContext: DPoPProofContext;
60
65
  private constructor();
61
- calculateThumbprint(): Promise<string>;
62
- getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string>;
63
- signWithDpopPrivateKey(payload: string): Promise<string>;
64
- isBoundToAlias(alias?: string): Promise<boolean>;
65
- static generateProof(input: GenerateProofInput): Promise<DPoP>;
66
66
  static assertHardwareBacked(alias?: string): Promise<void>;
67
+ static buildDPoPHeaders(input: GenerateProofInput): Promise<DPoPHeaders>;
67
68
  static deleteKeyPair(alias?: string): Promise<void>;
69
+ static generateProof(input: GenerateProofInput): Promise<DPoP>;
68
70
  static getKeyInfo(alias?: string): Promise<DPoPKeyInfo>;
69
71
  static hasKeyPair(alias?: string): Promise<boolean>;
70
72
  static rotateKeyPair(alias?: string): Promise<void>;
73
+ getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string>;
74
+ getPublicKeyThumbprint(): Promise<string>;
75
+ isBoundToAlias(alias?: string): Promise<boolean>;
76
+ signWithDPoPPrivateKey(payload: string): Promise<string>;
71
77
  }
72
78
  export {};
73
79
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAEA,KAAK,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,EAAE,IAAI,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpD,MAAM,MAAM,4BAA4B,GAAG,aAAa,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAC5G,MAAM,MAAM,wBAAwB,GAAG,UAAU,GAAG,qBAAqB,GAAG,WAAW,CAAC;AACxF,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,gBAAgB,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE;YACR,aAAa,CAAC,EAAE,MAAM,CAAC;YACvB,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;YAC7C,kBAAkB,EAAE,OAAO,CAAC;YAC5B,eAAe,EAAE,OAAO,CAAC;YACzB,uBAAuB,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAC;SAC/D,CAAC;QACF,GAAG,CAAC,EAAE;YACJ,sBAAsB,EAAE,OAAO,CAAC;YAChC,mBAAmB,EAAE,OAAO,CAAC;YAC7B,2BAA2B,CAAC,EAAE,4BAA4B,GAAG,IAAI,CAAC;YAClE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;YAC9B,iBAAiB,CAAC,EAAE,oBAAoB,CAAC;SAC1C,CAAC;KACH,CAAC;IACF,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACpC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAOF,qBAAa,IAAI;IACf,SAAgB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,SAAgB,YAAY,EAAE,gBAAgB,CAAC;IAE/C,OAAO;WAMa,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAInD,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC;WASjE,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;WAI5C,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;WAkBvD,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;WAIhD,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAI5C,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC;IAWlE,sBAAsB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIzC,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIhD,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAGtE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-dpop",
3
- "version": "0.4.0",
3
+ "version": "1.0.0",
4
4
  "description": "React Native library for DPoP proof generation and key management.",
5
5
  "keywords": [
6
6
  "android",
@@ -4,16 +4,7 @@ import type { UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
4
4
 
5
5
  export interface Spec extends TurboModule {
6
6
  assertHardwareBacked(alias: string | null): Promise<void>;
7
- calculateThumbprint(alias: string | null): Promise<string>;
8
7
  deleteKeyPair(alias: string | null): Promise<void>;
9
- getKeyInfo(alias: string | null): Promise<UnsafeObject>;
10
- getPublicKeyDer(alias: string | null): Promise<string>;
11
- getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
12
- getPublicKeyRaw(alias: string | null): Promise<string>;
13
- hasKeyPair(alias: string | null): Promise<boolean>;
14
- isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
15
- rotateKeyPair(alias: string | null): Promise<void>;
16
- signWithDpopPrivateKey(payload: string, alias: string | null): Promise<string>;
17
8
  generateProof(
18
9
  htu: string,
19
10
  htm: string,
@@ -23,12 +14,22 @@ export interface Spec extends TurboModule {
23
14
  kid: string | null,
24
15
  jti: string | null,
25
16
  iat: number | null,
26
- alias: string | null
17
+ alias: string | null,
18
+ requireHardwareBacked: boolean
27
19
  ): Promise<UnsafeObject>;
20
+ getKeyInfo(alias: string | null): Promise<UnsafeObject>;
21
+ getPublicKeyDer(alias: string | null): Promise<string>;
22
+ getPublicKeyJwk(alias: string | null): Promise<UnsafeObject>;
23
+ getPublicKeyRaw(alias: string | null): Promise<string>;
24
+ getPublicKeyThumbprint(alias: string | null): Promise<string>;
25
+ hasKeyPair(alias: string | null): Promise<boolean>;
26
+ isBoundToAlias(proof: string, alias: string | null): Promise<boolean>;
27
+ rotateKeyPair(alias: string | null): Promise<void>;
28
+ signWithDPoPPrivateKey(payload: string, alias: string | null): Promise<string>;
28
29
  }
29
30
 
30
- const nativeDpopModule =
31
+ const nativeDPoPModule =
31
32
  // eslint-disable-next-line dot-notation -- required by noPropertyAccessFromIndexSignature from @tsconfig/strictest
32
33
  TurboModuleRegistry.get<Spec>('ReactNativeDPoP') ?? (NativeModules['ReactNativeDPoP'] as Spec | undefined);
33
34
 
34
- export default nativeDpopModule as Spec;
35
+ export default nativeDPoPModule as Spec;
package/src/index.tsx CHANGED
@@ -3,8 +3,8 @@ import NativeReactNativeDPoP from './NativeReactNativeDPoP';
3
3
  type AdditionalClaims = Record<string, unknown>;
4
4
 
5
5
  export type PublicJwk = {
6
- kty: 'EC';
7
6
  crv: 'P-256';
7
+ kty: 'EC';
8
8
  x: string;
9
9
  y: string;
10
10
  };
@@ -16,50 +16,56 @@ export type AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STR
16
16
  export type IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE';
17
17
 
18
18
  export type DPoPKeyInfo = {
19
- alias: string;
20
- hasKeyPair: boolean;
21
19
  algorithm?: string;
20
+ alias: string;
22
21
  curve?: string;
23
- insideSecureHardware?: boolean;
24
22
  hardware?: {
25
23
  android?: {
26
- strongBoxAvailable: boolean;
27
- strongBoxBacked: boolean;
28
24
  securityLevel?: number;
29
25
  securityLevelName?: AndroidSecurityLevelName;
26
+ strongBoxAvailable: boolean;
27
+ strongBoxBacked: boolean;
30
28
  strongBoxFallbackReason?: SecureHardwareFallbackReason | null;
31
29
  };
32
30
  ios?: {
33
31
  secureEnclaveAvailable: boolean;
34
32
  secureEnclaveBacked: boolean;
33
+ secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
35
34
  securityLevel?: number | null;
36
35
  securityLevelName?: IOSSecurityLevelName;
37
- secureEnclaveFallbackReason?: SecureHardwareFallbackReason | null;
38
36
  };
39
37
  };
38
+ hasKeyPair: boolean;
39
+ insideSecureHardware?: boolean;
40
40
  };
41
41
 
42
42
  export type GenerateProofInput = {
43
- htu: string;
44
- htm: string;
45
- nonce?: string;
46
43
  accessToken?: string;
47
44
  additional?: AdditionalClaims;
48
- kid?: string;
49
- jti?: string;
50
- iat?: number;
51
45
  alias?: string;
46
+ htm: string;
47
+ htu: string;
48
+ iat?: number;
49
+ jti?: string;
50
+ kid?: string;
51
+ nonce?: string;
52
+ requireHardwareBacked?: boolean;
53
+ };
54
+
55
+ export type DPoPHeaders = {
56
+ Authorization?: string;
57
+ DPoP: string;
52
58
  };
53
59
 
54
60
  export type DPoPProofContext = {
55
- htu: string;
56
- htm: string;
57
- nonce: string | null;
58
- ath: string | null;
59
61
  additional: AdditionalClaims | null;
60
- kid: string | null;
61
- jti: string;
62
+ ath: string | null;
63
+ htm: string;
64
+ htu: string;
62
65
  iat: number;
66
+ jti: string;
67
+ kid: string | null;
68
+ nonce: string | null;
63
69
  };
64
70
 
65
71
  type GenerateProofResult = {
@@ -68,8 +74,8 @@ type GenerateProofResult = {
68
74
  };
69
75
 
70
76
  export class DPoP {
71
- public readonly proof: string;
72
77
  public readonly alias: string | undefined;
78
+ public readonly proof: string;
73
79
  public readonly proofContext: DPoPProofContext;
74
80
 
75
81
  private constructor(proof: string, proofContext: DPoPProofContext, alias?: string) {
@@ -78,27 +84,21 @@ export class DPoP {
78
84
  this.alias = alias;
79
85
  }
80
86
 
81
- public async calculateThumbprint(): Promise<string> {
82
- return NativeReactNativeDPoP.calculateThumbprint(this.alias ?? null);
87
+ public static async assertHardwareBacked(alias?: string): Promise<void> {
88
+ await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
83
89
  }
84
90
 
85
- public async getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string> {
86
- if (format === 'DER') {
87
- return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
88
- }
89
- if (format === 'RAW') {
90
- return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
91
- }
92
-
93
- return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null) as Promise<PublicJwk>;
94
- }
91
+ public static async buildDPoPHeaders(input: GenerateProofInput): Promise<DPoPHeaders> {
92
+ const dPoP = await DPoP.generateProof(input);
95
93
 
96
- public async signWithDpopPrivateKey(payload: string): Promise<string> {
97
- return NativeReactNativeDPoP.signWithDpopPrivateKey(payload, this.alias ?? null);
94
+ return {
95
+ DPoP: dPoP.proof,
96
+ ...(input.accessToken ? { Authorization: `DPoP ${input.accessToken}` } : {}),
97
+ };
98
98
  }
99
99
 
100
- public async isBoundToAlias(alias?: string): Promise<boolean> {
101
- return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
100
+ public static async deleteKeyPair(alias?: string): Promise<void> {
101
+ await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
102
102
  }
103
103
 
104
104
  public static async generateProof(input: GenerateProofInput): Promise<DPoP> {
@@ -112,20 +112,13 @@ export class DPoP {
112
112
  input.jti ?? null,
113
113
  // RN 0.75 Android bridge can crash when a nullable Double arrives as null.
114
114
  input.iat ?? Math.floor(Date.now() / 1000),
115
- input.alias ?? null
115
+ input.alias ?? null,
116
+ input.requireHardwareBacked ?? false
116
117
  )) as GenerateProofResult;
117
118
 
118
119
  return new DPoP(result.proof, result.proofContext, input.alias);
119
120
  }
120
121
 
121
- public static async assertHardwareBacked(alias?: string): Promise<void> {
122
- await NativeReactNativeDPoP.assertHardwareBacked(alias ?? null);
123
- }
124
-
125
- public static async deleteKeyPair(alias?: string): Promise<void> {
126
- await NativeReactNativeDPoP.deleteKeyPair(alias ?? null);
127
- }
128
-
129
122
  public static async getKeyInfo(alias?: string): Promise<DPoPKeyInfo> {
130
123
  return NativeReactNativeDPoP.getKeyInfo(alias ?? null) as Promise<DPoPKeyInfo>;
131
124
  }
@@ -137,4 +130,27 @@ export class DPoP {
137
130
  public static async rotateKeyPair(alias?: string): Promise<void> {
138
131
  await NativeReactNativeDPoP.rotateKeyPair(alias ?? null);
139
132
  }
133
+
134
+ public async getPublicKey(format: PublicKeyFormat): Promise<PublicJwk | string> {
135
+ if (format === 'DER') {
136
+ return NativeReactNativeDPoP.getPublicKeyDer(this.alias ?? null);
137
+ }
138
+ if (format === 'RAW') {
139
+ return NativeReactNativeDPoP.getPublicKeyRaw(this.alias ?? null);
140
+ }
141
+
142
+ return NativeReactNativeDPoP.getPublicKeyJwk(this.alias ?? null) as Promise<PublicJwk>;
143
+ }
144
+
145
+ public async getPublicKeyThumbprint(): Promise<string> {
146
+ return NativeReactNativeDPoP.getPublicKeyThumbprint(this.alias ?? null);
147
+ }
148
+
149
+ public async isBoundToAlias(alias?: string): Promise<boolean> {
150
+ return NativeReactNativeDPoP.isBoundToAlias(this.proof, alias ?? this.alias ?? null);
151
+ }
152
+
153
+ public async signWithDPoPPrivateKey(payload: string): Promise<string> {
154
+ return NativeReactNativeDPoP.signWithDPoPPrivateKey(payload, this.alias ?? null);
155
+ }
140
156
  }