react-native-dpop
v1.0.0
Published
React Native library for DPoP proof generation and key management.
Readme
react-native-dpop
React Native library for DPoP proof generation and key management.
Features
- Generate DPoP proofs (
dpop+jwt) signed with ES256 - Manage key pairs in the platform keystore
- Export the public key as
JWK,DER, orRAW - Calculate JWK thumbprints (
SHA-256, base64url) - Verify whether a proof is bound to a given key alias
- Retrieve non-sensitive key metadata, including secure hardware details
- Use Secure Enclave on iOS when available, with Keychain fallback
- Prefer StrongBox on Android when available, with hardware-backed fallback
Platform support
- Android
- iOS
Installation
npm install react-native-dpopFor iOS:
cd ios && pod installQuick start
import { DPoP } from 'react-native-dpop';
const dPoP = await DPoP.generateProof({
htu: 'https://api.example.com/token',
htm: 'POST',
accessToken: 'ACCESS_TOKEN',
nonce: 'SERVER_NONCE',
requireHardwareBacked: true,
});
const proof = dPoP.proof;
const thumbprint = await dPoP.getPublicKeyThumbprint();
const publicJwk = await dPoP.getPublicKey('JWK');
const keyInfo = await DPoP.getKeyInfo();API
Static methods
DPoP.generateProof(input): Promise<DPoP>DPoP.buildDPoPHeaders(input): Promise<DPoPHeaders>DPoP.assertHardwareBacked(alias?): Promise<void>DPoP.deleteKeyPair(alias?): Promise<void>DPoP.getKeyInfo(alias?): Promise<DPoPKeyInfo>DPoP.hasKeyPair(alias?): Promise<boolean>DPoP.rotateKeyPair(alias?): Promise<void>
Instance members
proof: stringproofContext: DPoPProofContextalias?: stringgetPublicKey(format): Promise<PublicJwk | string>getPublicKeyThumbprint(): Promise<string>signWithDPoPPrivateKey(payload): Promise<string>isBoundToAlias(alias?): Promise<boolean>
signWithDPoPPrivateKey()
signWithDPoPPrivateKey() reuses the same private key pair managed by the DPoP alias. It does not create or use a separate signing key.
This means:
- the signature is produced with the same key material used for DPoP proofs
- the active alias determines which private key is used
- if the alias points to a hardware-backed key, the same hardware-backed key is reused
- if the alias points to a fallback software-backed key, the same fallback key is reused
Recommended usage:
- use this only when you intentionally want to sign arbitrary payloads with the same DPoP key
- avoid treating it as a general-purpose application signing API
- if you need a different trust boundary or lifecycle, use a different alias or a different key management flow
Main types
GenerateProofInputDPoPHeadersDPoPProofContextDPoPKeyInfoPublicJwkPublicKeyFormat = 'JWK' | 'DER' | 'RAW'SecureHardwareFallbackReason = 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN'AndroidSecurityLevelName = 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX'IOSSecurityLevelName = 'SOFTWARE' | 'SECURE_ENCLAVE'
getKeyInfo()
getKeyInfo() returns shared fields plus platform-specific hardware metadata.
type DPoPKeyInfo = {
alias: string;
hasKeyPair: boolean;
algorithm?: string;
curve?: string;
insideSecureHardware?: boolean;
hardware?: {
android?: {
strongBoxAvailable: boolean;
strongBoxBacked: boolean;
securityLevel?: number;
securityLevelName?: 'SOFTWARE' | 'TRUSTED_ENVIRONMENT' | 'STRONGBOX';
strongBoxFallbackReason?: 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN' | null;
};
ios?: {
secureEnclaveAvailable: boolean;
secureEnclaveBacked: boolean;
securityLevel?: number | null;
securityLevelName?: 'SOFTWARE' | 'SECURE_ENCLAVE';
secureEnclaveFallbackReason?: 'UNAVAILABLE' | 'PROVIDER_ERROR' | 'POLICY_REJECTED' | 'UNKNOWN' | null;
};
};
};Security level semantics
securityLevel = 1Software-backed key materialsecurityLevel = 2Hardware-backed key material On Android this usually means TEE On iOS this means Secure EnclavesecurityLevel = 3Android StrongBox-backed keysecurityLevel = nullNo key material available, or the native platform did not report a numeric level
Fallback semantics
- On Android, the library tries StrongBox first when available
- On iOS, the library tries Secure Enclave first when available
- Fallback reasons are sanitized enums rather than raw native errors
- On iOS Simulator,
secureEnclaveFallbackReasonis expected to beUNAVAILABLE
buildDPoPHeaders()
buildDPoPHeaders() generates a proof and returns request headers ready to use.
const headers = await DPoP.buildDPoPHeaders({
htu: 'https://api.example.com/token',
htm: 'POST',
accessToken: 'ACCESS_TOKEN',
});
// {
// DPoP: '<proof>',
// Authorization: 'DPoP ACCESS_TOKEN',
// }If accessToken is omitted, only the DPoP header is returned.
Notes
- Default alias:
react-native-dpop htmis normalized to uppercaseathis derived fromaccessTokenwhen providedjtiandiatare auto-generated when omittedrequireHardwareBackedforces proof generation to fail instead of silently persisting a software-backed fallback key- For React Native 0.75 on Android, the library ensures
iatis sent as a number to avoid an older bridge nullability issue withDouble
Example apps
This repository includes two example apps:
examples/v0.75examples/v0.83
The root example script points to examples/v0.83.
Errors
Native rejections use codes such as:
ERR_DPOP_GENERATE_PROOFERR_DPOP_CALCULATE_THUMBPRINTERR_DPOP_PUBLIC_KEYERR_DPOP_SIGN_WITH_PRIVATE_KEYERR_DPOP_HAS_KEY_PAIRERR_DPOP_GET_KEY_INFOERR_DPOP_ROTATE_KEY_PAIRERR_DPOP_DELETE_KEY_PAIRERR_DPOP_ASSERT_HARDWARE_BACKEDERR_DPOP_IS_BOUND_TO_ALIAS
Contributing
License
MIT
