@atlasauth/expo-passkeys 0.1.1 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlasauth/expo-passkeys changelog
2
2
 
3
+ ## 0.3.0 — 2026-11-13
4
+
5
+ - Passkey sign-in uses the headless captcha solver when no `getCaptchaToken` is passed.
6
+ - `@atlasauth/js` is now a peer dependency, so the app and every Atlas SDK share one copy.
7
+
8
+ ## 0.2.0 — 2026-10-23
9
+ - **Passkey sign-in takes the sign-in captcha.** `authenticateWithPasskey()` accepts `captchaToken` (sent on the start) and `getCaptchaToken` (asked for a fresh token after a `CAPTCHA_REQUIRED` / `CAPTCHA_FAILED` refusal; the start is retried once). Needed when the app challenges every sign-in.
10
+ - Built on `@atlasauth/js` 0.16.0.
11
+
3
12
  ## 0.1.1
4
13
  - **`frontendApi` is validated at client creation.** A missing, empty or malformed value now throws an
5
14
  `AtlasConfigError` (from `@atlasauth/js`; `code: 'FRONTEND_API_REQUIRED'` or `'FRONTEND_API_INVALID'`)
package/README.md CHANGED
@@ -14,7 +14,7 @@ mapping between them.
14
14
  ## Native dependency
15
15
 
16
16
  ```sh
17
- npx expo install react-native-passkey
17
+ npx expo install @atlasauth/js react-native-passkey
18
18
  ```
19
19
 
20
20
  `react-native-passkey` is a native module: it needs a config plugin and a
@@ -64,5 +64,21 @@ if (result.status === 'complete' && result.ticket) {
64
64
  }
65
65
  ```
66
66
 
67
+ ### When the app challenges every sign-in
68
+
69
+ If the app asks for a security check on every sign-in, the sign-in start needs a captcha token.
70
+ Pass a solved `captchaToken`, or a `getCaptchaToken` callback, or both. The callback is called after
71
+ the server refuses the start (`CAPTCHA_REQUIRED` or `CAPTCHA_FAILED`). It receives the app's public
72
+ sign-in captcha settings (provider, site key). Run that provider's challenge, for example in a
73
+ WebView, and return the solved token. The start is then retried once with it.
74
+
75
+ ```ts
76
+ const result = await authenticateWithPasskey({
77
+ config,
78
+ passkey: Passkey,
79
+ getCaptchaToken: async ({ captcha }) => solveInWebView(captcha), // your own challenge screen
80
+ });
81
+ ```
82
+
67
83
  `toRegistrationFinishBody` / `toAssertionFinishBody` are exported as pure helpers
68
84
  if you want to drive the two HTTP calls yourself.
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@
12
12
  * register: POST /v1/client/me/passkeys/begin → Passkey.create → /finish
13
13
  * sign in : POST /v1/client/sign_ins/passkey/begin → Passkey.get → /finish
14
14
  */
15
- import type { FieldError, PasskeyAssertionBody, PasskeyRegistrationBody } from '@atlasauth/js';
15
+ import { type FieldError, type FlowCaptcha, type PasskeyAssertionBody, type PasskeyRegistrationBody } from '@atlasauth/js';
16
16
  import { type AtlasFapiConfig } from './client';
17
17
  import type { PasskeyCreateResult, PasskeyGetResult, ReactNativePasskey } from './passkey-native';
18
18
  export * from './client';
@@ -43,13 +43,37 @@ export interface PasskeySignInResult {
43
43
  attemptStatus?: string;
44
44
  errors: FieldError[];
45
45
  }
46
+ /** What {@link authenticateWithPasskey}'s `getCaptchaToken` is asked for. */
47
+ export interface PasskeyCaptchaTokenRequest {
48
+ /** Always `signIn`: the passkey begin takes the sign-in challenge. */
49
+ flow: 'signIn';
50
+ /**
51
+ * The instance's public sign-in captcha settings (provider, site key, widget
52
+ * mode) from `GET /v1/appearance`; null if they could not be read.
53
+ */
54
+ captcha: FlowCaptcha | null;
55
+ /** The refusal that prompted the ask. */
56
+ refused: 'CAPTCHA_REQUIRED' | 'CAPTCHA_FAILED';
57
+ }
46
58
  /**
47
59
  * Sign in with a passkey. Runs begin → platform ceremony → finish and returns
48
60
  * the attempt outcome: `complete` carries a one-time `ticket` to exchange for a
49
61
  * session (hand it to `@atlasauth/expo`), `needs_more` means a factor is still
50
62
  * owed.
63
+ *
64
+ * When the instance challenges every sign-in (an always-on sign-in captcha, or
65
+ * a force-challenge switch) the begin needs a `captcha_token`. Pass a solved
66
+ * `captchaToken` up front, and/or a `getCaptchaToken` callback: after a
67
+ * `CAPTCHA_REQUIRED` / `CAPTCHA_FAILED` refusal it is asked for a FRESH token
68
+ * (run the provider's challenge, e.g. in a WebView, with `captcha.siteKey`) and
69
+ * the begin is retried once. Without either, the refusal comes back as the
70
+ * result's error.
51
71
  */
52
72
  export declare function authenticateWithPasskey(opts: {
53
73
  config: AtlasFapiConfig;
54
74
  passkey: ReactNativePasskey;
75
+ /** A solved sign-in captcha token, sent on the first begin. */
76
+ captchaToken?: string;
77
+ /** Asked for a fresh token after a captcha refusal; the begin is then retried once. */
78
+ getCaptchaToken?: (request: PasskeyCaptchaTokenRequest) => Promise<string | null>;
55
79
  }): Promise<PasskeySignInResult>;
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ exports.toRegistrationFinishBody = toRegistrationFinishBody;
32
32
  exports.toAssertionFinishBody = toAssertionFinishBody;
33
33
  exports.registerPasskey = registerPasskey;
34
34
  exports.authenticateWithPasskey = authenticateWithPasskey;
35
+ const js_1 = require("@atlasauth/js");
35
36
  const client_1 = require("./client");
36
37
  __exportStar(require("./client"), exports);
37
38
  __exportStar(require("./passkey-native"), exports);
@@ -76,10 +77,40 @@ async function registerPasskey(opts) {
76
77
  * the attempt outcome: `complete` carries a one-time `ticket` to exchange for a
77
78
  * session (hand it to `@atlasauth/expo`), `needs_more` means a factor is still
78
79
  * owed.
80
+ *
81
+ * When the instance challenges every sign-in (an always-on sign-in captcha, or
82
+ * a force-challenge switch) the begin needs a `captcha_token`. Pass a solved
83
+ * `captchaToken` up front, and/or a `getCaptchaToken` callback: after a
84
+ * `CAPTCHA_REQUIRED` / `CAPTCHA_FAILED` refusal it is asked for a FRESH token
85
+ * (run the provider's challenge, e.g. in a WebView, with `captcha.siteKey`) and
86
+ * the begin is retried once. Without either, the refusal comes back as the
87
+ * result's error.
79
88
  */
80
89
  async function authenticateWithPasskey(opts) {
81
90
  const client = (0, client_1.createFapiClient)(opts.config);
82
- const begin = await client.post('/v1/client/sign_ins/passkey/begin', {});
91
+ const { captchaToken } = opts;
92
+ // With no callback, the headless solver `@atlasauth/expo` installs answers the captcha.
93
+ const headless = (0, js_1.getHeadlessCaptchaSolver)();
94
+ const getCaptchaToken = opts.getCaptchaToken ??
95
+ (headless
96
+ ? async (request) => request.captcha ? headless(request.captcha, { flow: 'signIn' }).catch(() => null) : null
97
+ : undefined);
98
+ const begin = await (0, js_1.beginPasskeySignIn)(client, {
99
+ captcha: captchaToken || getCaptchaToken
100
+ ? async ({ retry, refused }) => {
101
+ if (!retry)
102
+ return captchaToken ?? null;
103
+ if (!getCaptchaToken)
104
+ return null;
105
+ const settings = await (0, js_1.fetchInstanceSettings)(client);
106
+ return getCaptchaToken({
107
+ flow: 'signIn',
108
+ captcha: settings?.captchaFlows.signIn ?? null,
109
+ refused: refused ?? 'CAPTCHA_REQUIRED',
110
+ });
111
+ }
112
+ : null,
113
+ });
83
114
  if (!begin.ok || !begin.data)
84
115
  return { status: 'error', errors: begin.errors };
85
116
  const assertion = await opts.passkey.get(begin.data);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,12 +1,10 @@
1
1
  {
2
2
  "name": "@atlasauth/expo-passkeys",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
- "dependencies": {
7
- "@atlasauth/js": "0.6.0"
8
- },
9
6
  "peerDependencies": {
7
+ "@atlasauth/js": ">=0.40.0 <1.0.0",
10
8
  "react-native": ">=0.73",
11
9
  "react-native-passkey": ">=3"
12
10
  },
@@ -20,19 +18,21 @@
20
18
  },
21
19
  "devDependencies": {
22
20
  "typescript": "^5.6.3",
23
- "vitest": "^2.1.4"
21
+ "vitest": "^3.2.7",
22
+ "@atlasauth/js": "0.40.0"
24
23
  },
25
24
  "publishConfig": {
26
25
  "access": "public"
27
26
  },
28
27
  "files": [
29
28
  "dist",
29
+ "!dist/*.tsbuildinfo",
30
30
  "README.md",
31
31
  "CHANGELOG.md"
32
32
  ],
33
33
  "scripts": {
34
34
  "build": "tsc -p tsconfig.build.json",
35
- "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "typecheck": "tsgo -p tsconfig.json --noEmit --module preserve --moduleResolution bundler --incremental --tsBuildInfoFile node_modules/.cache/typecheck.tsbuildinfo",
36
36
  "test": "vitest run"
37
37
  }
38
38
  }