@bb-labs/pkce 0.0.2 → 0.0.4
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 +31 -92
- package/dist/index.d.ts +36 -0
- package/dist/index.js +47 -1
- package/dist/utils/base64.d.ts +5 -0
- package/dist/utils/base64.js +14 -0
- package/dist/utils/sha256.d.ts +11 -0
- package/dist/utils/sha256.js +114 -0
- package/package.json +11 -7
- package/dist/expo/index.d.ts +0 -10
- package/dist/expo/index.js +0 -55
- package/dist/node/index.d.ts +0 -10
- package/dist/node/index.js +0 -49
package/README.md
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
# @bb-labs/pkce
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 🎯 **Zero Dependencies**: No external crypto libraries required
|
|
8
|
-
- 🔄 **Cross-Platform**: Works in React Native (expo-crypto), Node.js (built-in crypto), and browsers
|
|
9
|
-
- 🚀 **Auto-Detection**: Automatically uses the best available crypto implementation
|
|
10
|
-
- 📦 **Tree-Shakable**: Import only what you need
|
|
3
|
+
Zero-dependency PKCE library with pure JavaScript SHA-256 implementation. Bring your own crypto - provide a random bytes generator for maximum compatibility.
|
|
11
4
|
|
|
12
5
|
## Installation
|
|
13
6
|
|
|
@@ -17,108 +10,54 @@ npm install @bb-labs/pkce
|
|
|
17
10
|
|
|
18
11
|
## Usage
|
|
19
12
|
|
|
20
|
-
### Automatic Environment Detection (Recommended)
|
|
21
|
-
|
|
22
13
|
```typescript
|
|
23
14
|
import { generateCodeVerifier, createCodeChallenge } from "@bb-labs/pkce";
|
|
24
15
|
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const challenge = await createCodeChallenge(verifier);
|
|
30
|
-
|
|
31
|
-
console.log("Verifier:", verifier);
|
|
32
|
-
console.log("Challenge:", challenge);
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
### Platform-Specific Imports
|
|
36
|
-
|
|
37
|
-
#### React Native / Expo
|
|
38
|
-
|
|
39
|
-
```typescript
|
|
40
|
-
import { generateCodeVerifier, createCodeChallenge } from "@bb-labs/pkce/expo";
|
|
41
|
-
|
|
42
|
-
// Make sure expo-crypto is installed in your React Native app
|
|
43
|
-
// npm install expo-crypto
|
|
44
|
-
|
|
45
|
-
const verifier = generateCodeVerifier();
|
|
46
|
-
const challenge = await createCodeChallenge(verifier);
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
#### Node.js
|
|
16
|
+
// Node.js
|
|
17
|
+
import { randomBytes } from "crypto";
|
|
18
|
+
const verifier = generateCodeVerifier(randomBytes);
|
|
19
|
+
const challenge = createCodeChallenge(verifier);
|
|
50
20
|
|
|
51
|
-
|
|
52
|
-
|
|
21
|
+
// Browser
|
|
22
|
+
const verifier = generateCodeVerifier((length) => {
|
|
23
|
+
const bytes = new Uint8Array(length);
|
|
24
|
+
crypto.getRandomValues(bytes);
|
|
25
|
+
return bytes;
|
|
26
|
+
});
|
|
27
|
+
const challenge = createCodeChallenge(verifier);
|
|
53
28
|
|
|
54
|
-
|
|
55
|
-
|
|
29
|
+
// Expo
|
|
30
|
+
import * as Crypto from "expo-crypto";
|
|
31
|
+
const verifier = generateCodeVerifier(Crypto.getRandomBytes);
|
|
32
|
+
const challenge = createCodeChallenge(verifier);
|
|
56
33
|
```
|
|
57
34
|
|
|
58
35
|
## API
|
|
59
36
|
|
|
60
|
-
### `generateCodeVerifier(): string`
|
|
61
|
-
|
|
62
|
-
Generates a cryptographically secure random code verifier (43-128 characters, base64url encoded).
|
|
63
|
-
|
|
64
|
-
### `createCodeChallenge(verifier: string): Promise<string>`
|
|
65
|
-
|
|
66
|
-
Creates a code challenge by SHA-256 hashing the verifier and base64url encoding the result.
|
|
67
|
-
|
|
68
|
-
## Requirements
|
|
69
|
-
|
|
70
|
-
### React Native / Expo Apps
|
|
37
|
+
### `generateCodeVerifier(getRandomBytes): string`
|
|
71
38
|
|
|
72
|
-
|
|
73
|
-
- The library will automatically detect and use expo-crypto
|
|
39
|
+
Generates a cryptographically secure code verifier (43 chars, base64url encoded).
|
|
74
40
|
|
|
75
|
-
|
|
41
|
+
- `getRandomBytes`: Function returning random bytes (Uint8Array, ArrayBuffer, or Buffer)
|
|
76
42
|
|
|
77
|
-
|
|
78
|
-
- No additional dependencies required
|
|
43
|
+
### `createCodeChallenge(verifier): string`
|
|
79
44
|
|
|
80
|
-
|
|
45
|
+
Creates SHA-256 code challenge from verifier (43 chars, base64url encoded).
|
|
81
46
|
|
|
82
|
-
|
|
83
|
-
- Or use a polyfill for older browsers
|
|
47
|
+
## Platform Support
|
|
84
48
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { generateCodeVerifier, createCodeChallenge } from "@bb-labs/pkce";
|
|
89
|
-
|
|
90
|
-
// 1. Generate verifier and challenge
|
|
91
|
-
const verifier = generateCodeVerifier();
|
|
92
|
-
const challenge = await createCodeChallenge(verifier);
|
|
93
|
-
|
|
94
|
-
// 2. Send challenge to authorization server
|
|
95
|
-
const authUrl =
|
|
96
|
-
`https://auth.example.com/oauth/authorize?` +
|
|
97
|
-
`client_id=your_client_id&` +
|
|
98
|
-
`redirect_uri=your_redirect_uri&` +
|
|
99
|
-
`response_type=code&` +
|
|
100
|
-
`code_challenge=${challenge}&` +
|
|
101
|
-
`code_challenge_method=S256`;
|
|
102
|
-
|
|
103
|
-
// 3. After user authorization, exchange code for tokens using the verifier
|
|
104
|
-
const tokenResponse = await fetch("https://auth.example.com/oauth/token", {
|
|
105
|
-
method: "POST",
|
|
106
|
-
body: new URLSearchParams({
|
|
107
|
-
grant_type: "authorization_code",
|
|
108
|
-
code: authorizationCode,
|
|
109
|
-
redirect_uri: redirectUri,
|
|
110
|
-
client_id: clientId,
|
|
111
|
-
code_verifier: verifier, // ← Send the original verifier
|
|
112
|
-
}),
|
|
113
|
-
});
|
|
114
|
-
```
|
|
49
|
+
Works in all JavaScript environments. Provide your platform's crypto random bytes function:
|
|
115
50
|
|
|
116
|
-
|
|
51
|
+
- **Node.js**: `crypto.randomBytes`
|
|
52
|
+
- **Browser**: `(length) => crypto.getRandomValues(new Uint8Array(length))`
|
|
53
|
+
- **Expo/React Native**: `expo-crypto.getRandomBytes`
|
|
117
54
|
|
|
118
|
-
|
|
55
|
+
## Implementation Details
|
|
119
56
|
|
|
120
|
-
-
|
|
121
|
-
-
|
|
57
|
+
- **SHA-256**: Pure JavaScript FIPS 180-4 implementation
|
|
58
|
+
- **Base64URL**: RFC 4648 compliant
|
|
59
|
+
- **Bundle size**: ~3KB minified
|
|
60
|
+
- **TypeScript**: Full type definitions included
|
|
122
61
|
|
|
123
62
|
## License
|
|
124
63
|
|
package/dist/index.d.ts
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random bytes generator function type
|
|
3
|
+
* Can return Buffer, Uint8Array, or ArrayBuffer
|
|
4
|
+
*/
|
|
5
|
+
export type RandomBytesGenerator = (length: number) => Uint8Array | ArrayBuffer | Buffer;
|
|
6
|
+
/**
|
|
7
|
+
* Generates a random code verifier for PKCE
|
|
8
|
+
* @param getRandomBytes - Function that generates cryptographically secure random bytes
|
|
9
|
+
* @returns Base64url-encoded code verifier (43 characters)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Node.js
|
|
13
|
+
* import { randomBytes } from 'crypto';
|
|
14
|
+
* const verifier = generateCodeVerifier(randomBytes);
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Expo
|
|
18
|
+
* import * as Crypto from 'expo-crypto';
|
|
19
|
+
* const verifier = generateCodeVerifier(Crypto.getRandomBytes);
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Browser
|
|
23
|
+
* const verifier = generateCodeVerifier((length) => {
|
|
24
|
+
* const bytes = new Uint8Array(length);
|
|
25
|
+
* crypto.getRandomValues(bytes);
|
|
26
|
+
* return bytes;
|
|
27
|
+
* });
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateCodeVerifier(getRandomBytes: RandomBytesGenerator): string;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a code challenge from a code verifier using SHA-256
|
|
32
|
+
* Uses pure JavaScript SHA-256 implementation
|
|
33
|
+
* @param verifier - The code verifier to hash
|
|
34
|
+
* @returns Base64url-encoded SHA-256 hash of the verifier (43 characters)
|
|
35
|
+
*/
|
|
36
|
+
export declare function createCodeChallenge(verifier: string): string;
|
package/dist/index.js
CHANGED
|
@@ -1 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
import { uint8ArrayToBase64Url } from "./utils/base64";
|
|
2
|
+
import { sha256 } from "./utils/sha256";
|
|
3
|
+
/**
|
|
4
|
+
* Generates a random code verifier for PKCE
|
|
5
|
+
* @param getRandomBytes - Function that generates cryptographically secure random bytes
|
|
6
|
+
* @returns Base64url-encoded code verifier (43 characters)
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* // Node.js
|
|
10
|
+
* import { randomBytes } from 'crypto';
|
|
11
|
+
* const verifier = generateCodeVerifier(randomBytes);
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* // Expo
|
|
15
|
+
* import * as Crypto from 'expo-crypto';
|
|
16
|
+
* const verifier = generateCodeVerifier(Crypto.getRandomBytes);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Browser
|
|
20
|
+
* const verifier = generateCodeVerifier((length) => {
|
|
21
|
+
* const bytes = new Uint8Array(length);
|
|
22
|
+
* crypto.getRandomValues(bytes);
|
|
23
|
+
* return bytes;
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
export function generateCodeVerifier(getRandomBytes) {
|
|
27
|
+
// Generate 32 bytes (256 bits) of random data
|
|
28
|
+
const randomBytes = getRandomBytes(32);
|
|
29
|
+
// Ensure we have a Uint8Array
|
|
30
|
+
const bytes = randomBytes instanceof Uint8Array
|
|
31
|
+
? randomBytes
|
|
32
|
+
: new Uint8Array(randomBytes);
|
|
33
|
+
// Convert to base64url encoding (RFC 4648)
|
|
34
|
+
return uint8ArrayToBase64Url(bytes);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a code challenge from a code verifier using SHA-256
|
|
38
|
+
* Uses pure JavaScript SHA-256 implementation
|
|
39
|
+
* @param verifier - The code verifier to hash
|
|
40
|
+
* @returns Base64url-encoded SHA-256 hash of the verifier (43 characters)
|
|
41
|
+
*/
|
|
42
|
+
export function createCodeChallenge(verifier) {
|
|
43
|
+
// Hash using pure JavaScript SHA-256
|
|
44
|
+
const hash = sha256(verifier);
|
|
45
|
+
// Convert to base64url encoding
|
|
46
|
+
return uint8ArrayToBase64Url(hash);
|
|
47
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a Uint8Array to base64url encoding (RFC 4648)
|
|
3
|
+
* Works in all JavaScript environments
|
|
4
|
+
*/
|
|
5
|
+
export function uint8ArrayToBase64Url(bytes) {
|
|
6
|
+
let binary = '';
|
|
7
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
8
|
+
binary += String.fromCharCode(bytes[i]);
|
|
9
|
+
}
|
|
10
|
+
return btoa(binary)
|
|
11
|
+
.replace(/\+/g, '-')
|
|
12
|
+
.replace(/\//g, '_')
|
|
13
|
+
.replace(/=/g, '');
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure JavaScript SHA-256 implementation
|
|
3
|
+
* Based on FIPS 180-4 specification
|
|
4
|
+
* Works in all JavaScript environments (Node.js, browsers, React Native, Expo)
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Computes SHA-256 hash of input data
|
|
8
|
+
* @param data - Input string or byte array
|
|
9
|
+
* @returns SHA-256 hash as Uint8Array (32 bytes)
|
|
10
|
+
*/
|
|
11
|
+
export declare function sha256(data: string | Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure JavaScript SHA-256 implementation
|
|
3
|
+
* Based on FIPS 180-4 specification
|
|
4
|
+
* Works in all JavaScript environments (Node.js, browsers, React Native, Expo)
|
|
5
|
+
*/
|
|
6
|
+
// SHA-256 constants (first 32 bits of the fractional parts of the cube roots of the first 64 primes)
|
|
7
|
+
const K = new Uint32Array([
|
|
8
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
9
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
10
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
11
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
12
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
13
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
14
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
15
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
|
16
|
+
]);
|
|
17
|
+
// Right rotate
|
|
18
|
+
function rotr(n, x) {
|
|
19
|
+
return (x >>> n) | (x << (32 - n));
|
|
20
|
+
}
|
|
21
|
+
// Convert string to UTF-8 bytes
|
|
22
|
+
function stringToBytes(str) {
|
|
23
|
+
const bytes = new Uint8Array(str.length);
|
|
24
|
+
for (let i = 0; i < str.length; i++) {
|
|
25
|
+
const code = str.charCodeAt(i);
|
|
26
|
+
if (code > 127) {
|
|
27
|
+
// Handle UTF-8 encoding for non-ASCII characters
|
|
28
|
+
return new TextEncoder().encode(str);
|
|
29
|
+
}
|
|
30
|
+
bytes[i] = code;
|
|
31
|
+
}
|
|
32
|
+
return bytes;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Computes SHA-256 hash of input data
|
|
36
|
+
* @param data - Input string or byte array
|
|
37
|
+
* @returns SHA-256 hash as Uint8Array (32 bytes)
|
|
38
|
+
*/
|
|
39
|
+
export function sha256(data) {
|
|
40
|
+
// Convert input to bytes
|
|
41
|
+
const message = typeof data === 'string' ? stringToBytes(data) : data;
|
|
42
|
+
// Pre-processing: adding padding bits
|
|
43
|
+
const msgLength = message.length;
|
|
44
|
+
const bitLength = msgLength * 8;
|
|
45
|
+
// Calculate padding length (message + 1 bit + zeros + 64-bit length = multiple of 512 bits)
|
|
46
|
+
const paddingLength = (msgLength + 9 + 63) & ~63; // Round up to nearest multiple of 64
|
|
47
|
+
const padded = new Uint8Array(paddingLength);
|
|
48
|
+
// Copy message
|
|
49
|
+
padded.set(message);
|
|
50
|
+
// Append '1' bit (0x80 = 10000000 in binary)
|
|
51
|
+
padded[msgLength] = 0x80;
|
|
52
|
+
// Append length in bits as 64-bit big-endian integer
|
|
53
|
+
const view = new DataView(padded.buffer);
|
|
54
|
+
view.setUint32(paddingLength - 4, bitLength >>> 0, false); // Low 32 bits
|
|
55
|
+
// Initialize hash values (first 32 bits of the fractional parts of the square roots of the first 8 primes)
|
|
56
|
+
const h = new Uint32Array([
|
|
57
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
58
|
+
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
|
59
|
+
]);
|
|
60
|
+
// Process message in 512-bit (64-byte) chunks
|
|
61
|
+
const w = new Uint32Array(64);
|
|
62
|
+
for (let chunkStart = 0; chunkStart < padded.length; chunkStart += 64) {
|
|
63
|
+
// Break chunk into sixteen 32-bit big-endian words
|
|
64
|
+
for (let i = 0; i < 16; i++) {
|
|
65
|
+
const offset = chunkStart + i * 4;
|
|
66
|
+
w[i] = (padded[offset] << 24) | (padded[offset + 1] << 16) |
|
|
67
|
+
(padded[offset + 2] << 8) | padded[offset + 3];
|
|
68
|
+
}
|
|
69
|
+
// Extend the sixteen 32-bit words into sixty-four 32-bit words
|
|
70
|
+
for (let i = 16; i < 64; i++) {
|
|
71
|
+
const s0 = rotr(7, w[i - 15]) ^ rotr(18, w[i - 15]) ^ (w[i - 15] >>> 3);
|
|
72
|
+
const s1 = rotr(17, w[i - 2]) ^ rotr(19, w[i - 2]) ^ (w[i - 2] >>> 10);
|
|
73
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) >>> 0;
|
|
74
|
+
}
|
|
75
|
+
// Initialize working variables
|
|
76
|
+
let a = h[0], b = h[1], c = h[2], d = h[3];
|
|
77
|
+
let e = h[4], f = h[5], g = h[6], hh = h[7];
|
|
78
|
+
// Main compression loop
|
|
79
|
+
for (let i = 0; i < 64; i++) {
|
|
80
|
+
const S1 = rotr(6, e) ^ rotr(11, e) ^ rotr(25, e);
|
|
81
|
+
const ch = (e & f) ^ (~e & g);
|
|
82
|
+
const temp1 = (hh + S1 + ch + K[i] + w[i]) >>> 0;
|
|
83
|
+
const S0 = rotr(2, a) ^ rotr(13, a) ^ rotr(22, a);
|
|
84
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
85
|
+
const temp2 = (S0 + maj) >>> 0;
|
|
86
|
+
hh = g;
|
|
87
|
+
g = f;
|
|
88
|
+
f = e;
|
|
89
|
+
e = (d + temp1) >>> 0;
|
|
90
|
+
d = c;
|
|
91
|
+
c = b;
|
|
92
|
+
b = a;
|
|
93
|
+
a = (temp1 + temp2) >>> 0;
|
|
94
|
+
}
|
|
95
|
+
// Add compressed chunk to current hash value
|
|
96
|
+
h[0] = (h[0] + a) >>> 0;
|
|
97
|
+
h[1] = (h[1] + b) >>> 0;
|
|
98
|
+
h[2] = (h[2] + c) >>> 0;
|
|
99
|
+
h[3] = (h[3] + d) >>> 0;
|
|
100
|
+
h[4] = (h[4] + e) >>> 0;
|
|
101
|
+
h[5] = (h[5] + f) >>> 0;
|
|
102
|
+
h[6] = (h[6] + g) >>> 0;
|
|
103
|
+
h[7] = (h[7] + hh) >>> 0;
|
|
104
|
+
}
|
|
105
|
+
// Produce the final hash value (big-endian)
|
|
106
|
+
const hash = new Uint8Array(32);
|
|
107
|
+
for (let i = 0; i < 8; i++) {
|
|
108
|
+
hash[i * 4 + 0] = (h[i] >>> 24) & 0xff;
|
|
109
|
+
hash[i * 4 + 1] = (h[i] >>> 16) & 0xff;
|
|
110
|
+
hash[i * 4 + 2] = (h[i] >>> 8) & 0xff;
|
|
111
|
+
hash[i * 4 + 3] = h[i] & 0xff;
|
|
112
|
+
}
|
|
113
|
+
return hash;
|
|
114
|
+
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bb-labs/pkce",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "Zero-dependency PKCE library using Web Crypto API for Node.js, browsers, React Native, and Expo",
|
|
5
5
|
"homepage": "https://github.com/beepbop-labs/pkce",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"pkce",
|
|
8
8
|
"pkce-challenge",
|
|
9
|
-
"pkce-verifier"
|
|
9
|
+
"pkce-verifier",
|
|
10
|
+
"oauth",
|
|
11
|
+
"oauth2",
|
|
12
|
+
"web-crypto",
|
|
13
|
+
"react-native",
|
|
14
|
+
"expo"
|
|
10
15
|
],
|
|
11
16
|
"author": "Beepbop",
|
|
12
17
|
"license": "MIT",
|
|
@@ -20,15 +25,14 @@
|
|
|
20
25
|
"README.md"
|
|
21
26
|
],
|
|
22
27
|
"exports": {
|
|
23
|
-
".": "./dist/index.js"
|
|
24
|
-
"./node": "./dist/node/index.js",
|
|
25
|
-
"./expo": "./dist/expo/index.js"
|
|
28
|
+
".": "./dist/index.js"
|
|
26
29
|
},
|
|
27
30
|
"scripts": {
|
|
28
31
|
"clean": "rm -rf dist",
|
|
29
32
|
"build": "npm run clean && tsc -p tsconfig.json",
|
|
30
|
-
"pack": "npm run build &&
|
|
33
|
+
"pack": "npm run build && rm -rf archive && mkdir -p archive && bun pm pack --destination ./archive && find ./archive -name '*.tgz' -exec mv {} ./archive/archive7.tgz \\;"
|
|
31
34
|
},
|
|
35
|
+
"dependencies": {},
|
|
32
36
|
"devDependencies": {
|
|
33
37
|
"@types/bun": "latest"
|
|
34
38
|
},
|
package/dist/expo/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generates a cryptographically secure random code verifier for PKCE
|
|
3
|
-
* Uses expo-crypto if available, otherwise throws an error
|
|
4
|
-
*/
|
|
5
|
-
export declare function generateCodeVerifier(): string;
|
|
6
|
-
/**
|
|
7
|
-
* Creates a code challenge from a code verifier using SHA-256
|
|
8
|
-
* Uses expo-crypto if available, otherwise throws an error
|
|
9
|
-
*/
|
|
10
|
-
export declare function createCodeChallenge(verifier: string): Promise<string>;
|
package/dist/expo/index.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generates a cryptographically secure random code verifier for PKCE
|
|
3
|
-
* Uses expo-crypto if available, otherwise throws an error
|
|
4
|
-
*/
|
|
5
|
-
export function generateCodeVerifier() {
|
|
6
|
-
try {
|
|
7
|
-
const Crypto = require("expo-crypto");
|
|
8
|
-
// Generate 32 bytes (256 bits) of random data
|
|
9
|
-
const randomBytes = Crypto.getRandomBytes(32);
|
|
10
|
-
// Convert to base64url encoding (RFC 4648)
|
|
11
|
-
return base64UrlEncode(randomBytes);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
throw new Error("expo-crypto is required for React Native PKCE operations. Install expo-crypto or use a different PKCE implementation.");
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Creates a code challenge from a code verifier using SHA-256
|
|
19
|
-
* Uses expo-crypto if available, otherwise throws an error
|
|
20
|
-
*/
|
|
21
|
-
export async function createCodeChallenge(verifier) {
|
|
22
|
-
try {
|
|
23
|
-
const Crypto = require("expo-crypto");
|
|
24
|
-
// Hash the verifier using SHA-256
|
|
25
|
-
const hashBuffer = await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, verifier, {
|
|
26
|
-
encoding: Crypto.CryptoEncoding.BASE64,
|
|
27
|
-
});
|
|
28
|
-
// Return base64url encoded hash
|
|
29
|
-
return base64UrlEncode(hashBuffer);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
throw new Error("expo-crypto is required for React Native PKCE operations. Install expo-crypto or use a different PKCE implementation.");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Converts input to base64url encoding (RFC 4648)
|
|
37
|
-
* Replaces '+' with '-', '/' with '_', and removes padding
|
|
38
|
-
*/
|
|
39
|
-
function base64UrlEncode(input) {
|
|
40
|
-
let base64;
|
|
41
|
-
if (typeof input === "string") {
|
|
42
|
-
// If input is already a base64 string, use it directly
|
|
43
|
-
base64 = input;
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
// Convert Uint8Array to base64
|
|
47
|
-
base64 = "";
|
|
48
|
-
for (let i = 0; i < input.length; i++) {
|
|
49
|
-
base64 += String.fromCharCode(input[i]);
|
|
50
|
-
}
|
|
51
|
-
base64 = btoa(base64);
|
|
52
|
-
}
|
|
53
|
-
// Convert to base64url
|
|
54
|
-
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
55
|
-
}
|
package/dist/node/index.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generates a cryptographically secure random code verifier for PKCE
|
|
3
|
-
* Node.js implementation using built-in crypto
|
|
4
|
-
*/
|
|
5
|
-
export declare function generateCodeVerifier(): string;
|
|
6
|
-
/**
|
|
7
|
-
* Creates a code challenge from a code verifier using SHA-256
|
|
8
|
-
* Node.js implementation using built-in crypto
|
|
9
|
-
*/
|
|
10
|
-
export declare function createCodeChallenge(verifier: string): Promise<string>;
|
package/dist/node/index.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generates a cryptographically secure random code verifier for PKCE
|
|
3
|
-
* Node.js implementation using built-in crypto
|
|
4
|
-
*/
|
|
5
|
-
export function generateCodeVerifier() {
|
|
6
|
-
try {
|
|
7
|
-
const { randomBytes } = require("crypto");
|
|
8
|
-
// Generate 32 bytes (256 bits) of random data
|
|
9
|
-
const randomBytesData = randomBytes(32);
|
|
10
|
-
// Convert to base64url encoding (RFC 4648)
|
|
11
|
-
return base64UrlEncode(randomBytesData);
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
throw new Error("Node.js crypto is required for server-side PKCE operations.");
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Creates a code challenge from a code verifier using SHA-256
|
|
19
|
-
* Node.js implementation using built-in crypto
|
|
20
|
-
*/
|
|
21
|
-
export async function createCodeChallenge(verifier) {
|
|
22
|
-
try {
|
|
23
|
-
const { createHash } = require("crypto");
|
|
24
|
-
// Hash the verifier using SHA-256
|
|
25
|
-
const hash = createHash("sha256").update(verifier).digest();
|
|
26
|
-
// Return base64url encoded hash
|
|
27
|
-
return base64UrlEncode(hash);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
throw new Error("Node.js crypto is required for server-side PKCE operations.");
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Converts input to base64url encoding (RFC 4648)
|
|
35
|
-
* Replaces '+' with '-', '/' with '_', and removes padding
|
|
36
|
-
*/
|
|
37
|
-
function base64UrlEncode(input) {
|
|
38
|
-
let base64;
|
|
39
|
-
if (typeof input === "string") {
|
|
40
|
-
// If input is already a base64 string, use it directly
|
|
41
|
-
base64 = input;
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
// Convert Buffer to base64
|
|
45
|
-
base64 = input.toString("base64");
|
|
46
|
-
}
|
|
47
|
-
// Convert to base64url
|
|
48
|
-
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
49
|
-
}
|