phonelink 0.1.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 ADDED
@@ -0,0 +1,92 @@
1
+ # phonelink
2
+
3
+ Phone number verification for Expo and React Native apps. Phonelink handles the entire verification flow — your app opens a secure browser session, the user verifies their phone number, and your server validates the resulting JWT.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install phonelink
9
+ ```
10
+
11
+ ### Expo peer dependencies
12
+
13
+ The client-side module requires `expo-crypto` and `expo-web-browser`:
14
+
15
+ ```bash
16
+ npx expo install expo-crypto expo-web-browser
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ### 1. Client — start the verification flow
22
+
23
+ ```typescript
24
+ import { phonelink } from "phonelink/expo";
25
+
26
+ const result = await phonelink.verify("your-client-id");
27
+
28
+ if (result) {
29
+ // Send result.token and result.nonce to your backend
30
+ await fetch("/api/verify-phone", {
31
+ method: "POST",
32
+ body: JSON.stringify({ token: result.token, nonce: result.nonce }),
33
+ });
34
+ }
35
+ ```
36
+
37
+ `phonelink.verify` opens a secure in-app browser where the user completes phone verification. It returns `{ token, nonce }` on success, or `null` if the user cancels.
38
+
39
+ | Parameter | Type | Description |
40
+ |---------------|----------|-------------------------------------------------------|
41
+ | `clientId` | `string` | Your Phonelink client ID |
42
+ | `redirectUrl` | `string` | Deep link URI for your app (default `phonelink://verify`) |
43
+
44
+ ### 2. Server — validate the token
45
+
46
+ ```typescript
47
+ import { verifyPhonelinkToken } from "phonelink/server";
48
+
49
+ const payload = await verifyPhonelinkToken(token, nonce, "your-client-id");
50
+
51
+ console.log(payload.phone_e164); // "+14155551234"
52
+ console.log(payload.verified); // true
53
+ ```
54
+
55
+ `verifyPhonelinkToken` verifies the JWT signature against the Phonelink JWKS endpoint, checks the issuer and audience, and validates the nonce and verification status. It throws if anything is invalid.
56
+
57
+ | Parameter | Type | Description |
58
+ |-----------------|----------|--------------------------------------------|
59
+ | `token` | `string` | The JWT returned from the client flow |
60
+ | `expectedNonce` | `string` | The nonce returned alongside the token |
61
+ | `expectedAud` | `string` | Your client ID (must match the token audience) |
62
+
63
+ ## Payload
64
+
65
+ The verified token resolves to a `PhonelinkPayload`:
66
+
67
+ ```typescript
68
+ interface PhonelinkPayload {
69
+ phone_e164: string; // E.164 formatted phone number
70
+ verified: boolean; // Whether the phone number was verified
71
+ method: string; // Verification method used
72
+ provider: string; // Verification provider
73
+ nonce: string; // Nonce for replay protection
74
+ sub: string; // Subject identifier
75
+ iss: string; // Issuer
76
+ aud: string; // Audience (your client ID)
77
+ iat: number; // Issued at (unix timestamp)
78
+ exp: number; // Expiry (unix timestamp)
79
+ jti: string; // Unique token identifier
80
+ }
81
+ ```
82
+
83
+ ## Security
84
+
85
+ - Tokens are signed JWTs verified against the Phonelink JWKS endpoint
86
+ - Nonce validation prevents replay attacks — always forward the nonce from the client and check it on the server
87
+ - The audience claim is checked to ensure the token was issued for your application
88
+ - Token expiry is enforced automatically by the JWT verification
89
+
90
+ ## License
91
+
92
+ MIT
@@ -1,6 +1,6 @@
1
1
  // src/shared/constants.ts
2
- var PHONELINK_URL = "https://phonelink-web-git-new-base-vrl.vercel.app/auth";
3
- var EXPECTED_ISSUER = "https://auth.phone.link";
2
+ var PHONELINK_URL = "https://phone.link/auth";
3
+ var EXPECTED_ISSUER = "https://phone.link";
4
4
  function buildAuthUrl(clientId, redirectUrl, nonce) {
5
5
  return `${PHONELINK_URL}?client_id=${encodeURIComponent(clientId)}&redirect_url=${encodeURIComponent(redirectUrl)}&nonce=${nonce}`;
6
6
  }
@@ -37,7 +37,7 @@ var Crypto = __toESM(require("expo-crypto"));
37
37
  var WebBrowser = __toESM(require("expo-web-browser"));
38
38
 
39
39
  // src/shared/constants.ts
40
- var PHONELINK_URL = "https://phonelink-web-git-new-base-vrl.vercel.app/auth";
40
+ var PHONELINK_URL = "https://phone.link/auth";
41
41
  function buildAuthUrl(clientId, redirectUrl, nonce) {
42
42
  return `${PHONELINK_URL}?client_id=${encodeURIComponent(clientId)}&redirect_url=${encodeURIComponent(redirectUrl)}&nonce=${nonce}`;
43
43
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildAuthUrl
3
- } from "../chunk-27WHFHUI.mjs";
3
+ } from "../chunk-7HCSQUU2.mjs";
4
4
 
5
5
  // src/expo/index.ts
6
6
  import * as Crypto from "expo-crypto";
@@ -26,11 +26,11 @@ module.exports = __toCommonJS(server_exports);
26
26
  var import_jose = require("jose");
27
27
 
28
28
  // src/shared/constants.ts
29
- var EXPECTED_ISSUER = "https://auth.phone.link";
29
+ var EXPECTED_ISSUER = "https://phone.link";
30
30
 
31
31
  // src/server/index.ts
32
32
  var JWKS = (0, import_jose.createRemoteJWKSet)(
33
- new URL("https://auth.phone.link/.well-known/jwks.json")
33
+ new URL("https://phone.link/.well-known/jwks.json")
34
34
  );
35
35
  async function verifyPhonelinkToken(token, expectedNonce, expectedAud) {
36
36
  const { payload } = await (0, import_jose.jwtVerify)(token, JWKS, {
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  EXPECTED_ISSUER
3
- } from "../chunk-27WHFHUI.mjs";
3
+ } from "../chunk-7HCSQUU2.mjs";
4
4
 
5
5
  // src/server/index.ts
6
6
  import { createRemoteJWKSet, jwtVerify } from "jose";
7
7
  var JWKS = createRemoteJWKSet(
8
- new URL("https://auth.phone.link/.well-known/jwks.json")
8
+ new URL("https://phone.link/.well-known/jwks.json")
9
9
  );
10
10
  async function verifyPhonelinkToken(token, expectedNonce, expectedAud) {
11
11
  const { payload } = await jwtVerify(token, JWKS, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "phonelink",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Phone number verification SDK",
5
5
  "exports": {
6
6
  "./expo": {