@hawcx/react-native-sdk 1.0.7 → 1.1.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 +3 -6
- package/HawcxReactNative.podspec +2 -2
- package/README.md +327 -109
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/hawcx/reactnative/HawcxEventDispatcher.kt +4 -0
- package/android/src/main/java/com/hawcx/reactnative/HawcxReactNativeModule.kt +324 -1
- package/android/src/main/java/com/hawcx/reactnative/v6/HawcxV6Bridge.kt +402 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/HawcxFramework +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Info.plist +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.abi.json +22143 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.private.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/HawcxFramework +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Info.plist +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.abi.json +22143 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/arm64-apple-ios-simulator.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.abi.json +22143 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/Modules/HawcxFramework.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +649 -21
- package/ios/Frameworks/HawcxFramework.xcframework/ios-arm64_x86_64-simulator/HawcxFramework.framework/_CodeSignature/CodeResources +21 -21
- package/ios/HawcxReactNative.m +56 -0
- package/ios/HawcxReactNative.swift +380 -1
- package/ios/HawcxV6BridgeSupport.swift +468 -0
- package/lib/commonjs/index.js +326 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/v6Normalization.js +325 -0
- package/lib/commonjs/v6Normalization.js.map +1 -0
- package/lib/commonjs/v6State.js +186 -0
- package/lib/commonjs/v6State.js.map +1 -0
- package/lib/commonjs/v6Types.js +2 -0
- package/lib/commonjs/v6Types.js.map +1 -0
- package/lib/commonjs/v6WebLogin.js +101 -0
- package/lib/commonjs/v6WebLogin.js.map +1 -0
- package/lib/module/index.js +287 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/v6Normalization.js +318 -0
- package/lib/module/v6Normalization.js.map +1 -0
- package/lib/module/v6State.js +173 -0
- package/lib/module/v6State.js.map +1 -0
- package/lib/module/v6Types.js +2 -0
- package/lib/module/v6Types.js.map +1 -0
- package/lib/module/v6WebLogin.js +92 -0
- package/lib/module/v6WebLogin.js.map +1 -0
- package/lib/typescript/index.d.ts +83 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/v6Normalization.d.ts +3 -0
- package/lib/typescript/v6Normalization.d.ts.map +1 -0
- package/lib/typescript/v6State.d.ts +13 -0
- package/lib/typescript/v6State.d.ts.map +1 -0
- package/lib/typescript/v6Types.d.ts +157 -0
- package/lib/typescript/v6Types.d.ts.map +1 -0
- package/lib/typescript/v6WebLogin.d.ts +32 -0
- package/lib/typescript/v6WebLogin.d.ts.map +1 -0
- package/package.json +21 -9
- package/src/index.ts +477 -0
- package/src/v6Normalization.ts +356 -0
- package/src/v6State.ts +238 -0
- package/src/v6Types.ts +194 -0
- package/src/v6WebLogin.ts +154 -0
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
- package/android/gradlew +0 -185
- package/android/gradlew.bat +0 -89
- package/android/libs/hawcx-5.1.2.aar +0 -0
- package/docs/RELEASE.md +0 -129
- package/example/README.md +0 -59
- package/example/android/app/build.gradle +0 -126
- package/example/android/app/debug.keystore +0 -0
- package/example/android/app/proguard-rules.pro +0 -10
- package/example/android/app/src/debug/AndroidManifest.xml +0 -9
- package/example/android/app/src/main/AndroidManifest.xml +0 -27
- package/example/android/app/src/main/java/com/hawcx/example/MainActivity.kt +0 -22
- package/example/android/app/src/main/java/com/hawcx/example/MainApplication.kt +0 -45
- package/example/android/app/src/main/res/drawable/rn_edit_text_material.xml +0 -36
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/example/android/app/src/main/res/values/strings.xml +0 -3
- package/example/android/app/src/main/res/values/styles.xml +0 -9
- package/example/android/build.gradle +0 -35
- package/example/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/example/android/gradle/wrapper/gradle-wrapper.properties +0 -7
- package/example/android/gradle.properties +0 -41
- package/example/android/gradlew +0 -249
- package/example/android/gradlew.bat +0 -92
- package/example/android/local.properties +0 -2
- package/example/android/settings.gradle +0 -38
- package/example/app.json +0 -4
- package/example/babel.config.js +0 -3
- package/example/e2e/README.md +0 -17
- package/example/e2e/hawcx-login.yaml +0 -14
- package/example/index.js +0 -5
- package/example/ios/.xcode.env +0 -11
- package/example/ios/HawcxExampleApp/AppDelegate.h +0 -6
- package/example/ios/HawcxExampleApp/AppDelegate.mm +0 -31
- package/example/ios/HawcxExampleApp/Images.xcassets/AppIcon.appiconset/Contents.json +0 -53
- package/example/ios/HawcxExampleApp/Images.xcassets/Contents.json +0 -6
- package/example/ios/HawcxExampleApp/Info.plist +0 -55
- package/example/ios/HawcxExampleApp/LaunchScreen.storyboard +0 -47
- package/example/ios/HawcxExampleApp/PrivacyInfo.xcprivacy +0 -37
- package/example/ios/HawcxExampleApp/main.m +0 -10
- package/example/ios/HawcxExampleApp.xcodeproj/project.pbxproj +0 -704
- package/example/ios/HawcxExampleApp.xcodeproj/project.xcworkspace/xcuserdata/agambhullar.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/HawcxExampleApp.xcodeproj/xcshareddata/xcschemes/HawcxExampleApp.xcscheme +0 -90
- package/example/ios/HawcxExampleApp.xcodeproj/xcuserdata/agambhullar.xcuserdatad/xcschemes/xcschememanagement.plist +0 -16
- package/example/ios/HawcxExampleApp.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/HawcxExampleAppTests/HawcxExampleAppTests.m +0 -66
- package/example/ios/HawcxExampleAppTests/Info.plist +0 -24
- package/example/ios/Podfile +0 -79
- package/example/ios/Podfile.lock +0 -1290
- package/example/metro.config.js +0 -16
- package/example/package-lock.json +0 -13220
- package/example/package.json +0 -30
- package/example/src/App.tsx +0 -755
- package/example/src/hawcx.config.ts +0 -25
- package/example/tsconfig.json +0 -8
- package/ios/Frameworks/.keep +0 -0
- package/lib/typescript/__tests__/index.test.d.ts +0 -2
- package/lib/typescript/__tests__/index.test.d.ts.map +0 -1
- package/react_mobile_sdk_plan.md +0 -242
- package/src/__tests__/index.test.ts +0 -206
package/CHANGELOG.md
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [1.0
|
|
3
|
+
## [1.1.0] - YYYY-MM-DD
|
|
4
4
|
- TODO: add release notes
|
|
5
5
|
|
|
6
|
-
## [1.0.
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
## [1.0.5] - YYYY-MM-DD
|
|
10
|
-
- TODO: add release notes
|
|
6
|
+
## [1.0.8] - 2026-01-21
|
|
7
|
+
- Android biometrics restriction issue fixed
|
|
11
8
|
|
|
12
9
|
## [1.0.4] - 2025-11-28
|
|
13
10
|
- Include Android sources in npm package and clarify linking error message.
|
package/HawcxReactNative.podspec
CHANGED
|
@@ -4,10 +4,10 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
|
4
4
|
Pod::Spec.new do |s|
|
|
5
5
|
s.name = 'HawcxReactNative'
|
|
6
6
|
s.version = package['version']
|
|
7
|
-
s.summary = 'React Native bindings for the Hawcx
|
|
7
|
+
s.summary = 'React Native bindings for the Hawcx mobile authentication SDKs (V5 + V6).'
|
|
8
8
|
s.description = <<-DESC
|
|
9
9
|
Production-grade React Native bridge that wraps HawcxFramework (iOS) to expose
|
|
10
|
-
V5 authentication,
|
|
10
|
+
Hawcx V5 and V6 authentication, device trust, push, and web session flows to JavaScript callers.
|
|
11
11
|
DESC
|
|
12
12
|
s.homepage = 'https://github.com/hawcx/reactnative_sdk'
|
|
13
13
|
s.license = { :type => 'MIT', :file => 'LICENSE' }
|
package/README.md
CHANGED
|
@@ -1,176 +1,394 @@
|
|
|
1
1
|
# Hawcx React Native SDK
|
|
2
2
|
|
|
3
|
-
Official React Native bindings for the Hawcx
|
|
3
|
+
Official React Native bindings for the Hawcx mobile authentication platform. The package
|
|
4
|
+
wraps the production Hawcx iOS and Android SDKs so you can ship the current V6 adaptive
|
|
5
|
+
flow in a single cross-platform API while keeping existing V5 utilities available during
|
|
6
|
+
migration.
|
|
7
|
+
|
|
8
|
+
## What This Package Includes
|
|
9
|
+
|
|
10
|
+
- V6 adaptive authentication via `useHawcxV6Auth`, `startV6Flow`, and `hawcxV6Client`
|
|
11
|
+
- Production native iOS and Android SDK integrations under the hood
|
|
12
|
+
- Redirect, approval polling, and QR approval helpers for V6 flows
|
|
13
|
+
- Existing V5 auth and push/session helpers for apps already in production
|
|
4
14
|
|
|
5
15
|
## Requirements
|
|
6
16
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
17
|
+
- React Native 0.73+
|
|
18
|
+
- iOS 17.5+
|
|
19
|
+
- Android API 26+
|
|
20
|
+
- OAuth client credentials kept on your backend
|
|
10
21
|
|
|
11
22
|
## Installation
|
|
12
23
|
|
|
24
|
+
Add the package:
|
|
25
|
+
|
|
13
26
|
```bash
|
|
14
|
-
npm install @hawcx/react-native-sdk
|
|
15
|
-
# or yarn add @hawcx/react-native-sdk
|
|
27
|
+
npm install @hawcx/react-native-sdk
|
|
16
28
|
```
|
|
17
29
|
|
|
30
|
+
Pin to the released version your team has approved for production.
|
|
31
|
+
|
|
18
32
|
### iOS
|
|
19
33
|
|
|
20
|
-
|
|
34
|
+
Install pods after adding the package:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
21
37
|
cd ios
|
|
22
38
|
pod install
|
|
23
39
|
cd ..
|
|
24
40
|
```
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
The Podspec vendors `HawcxFramework.xcframework` automatically, so no manual iOS
|
|
43
|
+
framework setup is required.
|
|
27
44
|
|
|
28
45
|
### Android
|
|
29
46
|
|
|
30
|
-
|
|
47
|
+
The React Native package depends on the released Hawcx Android SDK, so your Android app
|
|
48
|
+
must be able to resolve the Hawcx Maven repository.
|
|
49
|
+
|
|
50
|
+
Add the repository in `android/settings.gradle`:
|
|
51
|
+
|
|
52
|
+
```groovy
|
|
53
|
+
dependencyResolutionManagement {
|
|
54
|
+
repositories {
|
|
55
|
+
google()
|
|
56
|
+
mavenCentral()
|
|
57
|
+
maven {
|
|
58
|
+
url = uri("https://raw.githubusercontent.com/hawcx/hawcx_android_sdk/main/maven")
|
|
59
|
+
metadataSources {
|
|
60
|
+
mavenPom()
|
|
61
|
+
artifact()
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The hosted Hawcx Maven repository is public. You do not need a GitHub token for the
|
|
69
|
+
standard React Native setup.
|
|
31
70
|
|
|
32
|
-
|
|
71
|
+
If your Android project still bundles a local `hawcx-*.aar` or uses `flatDir { dirs("libs") }`,
|
|
72
|
+
remove that and let Gradle resolve the native SDK from Maven.
|
|
73
|
+
|
|
74
|
+
If Gradle has cached an older dependency graph, run:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cd android
|
|
78
|
+
./gradlew clean
|
|
79
|
+
cd ..
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## V6 Quick Start
|
|
83
|
+
|
|
84
|
+
Initialize the SDK once during app bootstrap:
|
|
33
85
|
|
|
34
86
|
```tsx
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
87
|
+
import { initialize } from '@hawcx/react-native-sdk';
|
|
88
|
+
|
|
89
|
+
await initialize({
|
|
90
|
+
projectApiKey: '<YOUR_CONFIG_ID>',
|
|
91
|
+
baseUrl: 'https://stage-api.hawcx.com',
|
|
92
|
+
autoPollApprovals: true,
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Initialization Notes
|
|
97
|
+
|
|
98
|
+
- `projectApiKey` is the Hawcx value provisioned for this integration. In current public
|
|
99
|
+
releases, this is the same value you may receive as your project API key / Config ID.
|
|
100
|
+
- `baseUrl` should point to your Hawcx tenant host root. Do not append `/v1`, `/auth`,
|
|
101
|
+
or `/hc_auth` yourself.
|
|
102
|
+
- `autoPollApprovals` defaults to `true`, which is the right choice for most apps.
|
|
103
|
+
- `relyingParty` is optional. Set it only when your backend expects the
|
|
104
|
+
`X-Relying-Party` header for this integration.
|
|
105
|
+
- `oauthConfig` is not required for the recommended V6 flow. Keep OAuth credentials on
|
|
106
|
+
your backend.
|
|
107
|
+
|
|
108
|
+
## How V6 Works
|
|
109
|
+
|
|
110
|
+
1. Initialize the package with your Config ID and tenant host.
|
|
111
|
+
2. Start a flow, usually `signin`, with the user's identifier.
|
|
112
|
+
3. Render the next prompt Hawcx returns.
|
|
113
|
+
4. Send the user's input back to the SDK.
|
|
114
|
+
5. When the flow completes, send the authorization code to your backend.
|
|
115
|
+
6. Let your backend exchange the code and create the app session.
|
|
116
|
+
|
|
117
|
+
The native SDKs handle protocol requests, PKCE when needed, trusted-device storage,
|
|
118
|
+
device-trust processing, and approval polling.
|
|
119
|
+
|
|
120
|
+
## Build an Auth Screen
|
|
121
|
+
|
|
122
|
+
The recommended React Native integration shape is a screen or coordinator that:
|
|
123
|
+
|
|
124
|
+
1. holds the current `HawcxV6AuthState`
|
|
125
|
+
2. starts the flow
|
|
126
|
+
3. reacts to the current prompt
|
|
127
|
+
4. forwards the user's input back to the SDK
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { useState } from 'react';
|
|
131
|
+
import { Button, Text, TextInput, View } from 'react-native';
|
|
132
|
+
import {
|
|
133
|
+
useHawcxV6Auth,
|
|
134
|
+
type HawcxV6Method,
|
|
135
|
+
} from '@hawcx/react-native-sdk';
|
|
136
|
+
|
|
137
|
+
export function V6AuthScreen() {
|
|
138
|
+
const [identifier, setIdentifier] = useState('');
|
|
139
|
+
const [code, setCode] = useState('');
|
|
140
|
+
const [totp, setTotp] = useState('');
|
|
141
|
+
const v6 = useHawcxV6Auth(undefined, { flowType: 'signin' });
|
|
142
|
+
|
|
143
|
+
const renderPrompt = () => {
|
|
144
|
+
switch (v6.state.status) {
|
|
145
|
+
case 'select_method':
|
|
146
|
+
return v6.state.prompt?.prompt.type === 'select_method'
|
|
147
|
+
? v6.state.prompt.prompt.methods.map((method: HawcxV6Method) => (
|
|
148
|
+
<Button
|
|
149
|
+
key={method.id}
|
|
150
|
+
title={method.label}
|
|
151
|
+
onPress={() => void v6.selectMethod(method.id)}
|
|
152
|
+
/>
|
|
153
|
+
))
|
|
154
|
+
: null;
|
|
155
|
+
|
|
156
|
+
case 'enter_code':
|
|
157
|
+
return (
|
|
158
|
+
<>
|
|
159
|
+
<TextInput value={code} onChangeText={setCode} keyboardType="number-pad" />
|
|
160
|
+
<Button title="Continue" onPress={() => void v6.submitCode(code)} />
|
|
161
|
+
</>
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
case 'enter_totp':
|
|
165
|
+
return (
|
|
166
|
+
<>
|
|
167
|
+
<TextInput value={totp} onChangeText={setTotp} />
|
|
168
|
+
<Button title="Continue" onPress={() => void v6.submitTotp(totp)} />
|
|
169
|
+
</>
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
case 'await_approval':
|
|
173
|
+
return <Text>Waiting for approval...</Text>;
|
|
174
|
+
|
|
175
|
+
case 'redirect':
|
|
176
|
+
return <Text>Continue in the browser to finish this step.</Text>;
|
|
177
|
+
|
|
178
|
+
default:
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<View>
|
|
185
|
+
<TextInput value={identifier} onChangeText={setIdentifier} />
|
|
186
|
+
<Button
|
|
187
|
+
title="Continue"
|
|
188
|
+
onPress={() =>
|
|
189
|
+
void v6.start({
|
|
190
|
+
flowType: 'signin',
|
|
191
|
+
identifier: identifier.trim(),
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
/>
|
|
195
|
+
{renderPrompt()}
|
|
196
|
+
</View>
|
|
197
|
+
);
|
|
50
198
|
}
|
|
51
199
|
```
|
|
52
200
|
|
|
53
|
-
|
|
201
|
+
### V6 Flow Types
|
|
202
|
+
|
|
203
|
+
`flowType` supports:
|
|
204
|
+
|
|
205
|
+
- `signin`
|
|
206
|
+
- `signup`
|
|
207
|
+
- `account_manage`
|
|
54
208
|
|
|
55
|
-
|
|
209
|
+
Most apps should start with `signin`.
|
|
56
210
|
|
|
57
|
-
|
|
211
|
+
## Redirect Handling
|
|
58
212
|
|
|
59
|
-
|
|
213
|
+
When the current prompt is `redirect`, open the provided URL in the browser and forward
|
|
214
|
+
the return URL back into the SDK:
|
|
60
215
|
|
|
61
216
|
```tsx
|
|
62
|
-
import
|
|
63
|
-
import {
|
|
217
|
+
import { useEffect } from 'react';
|
|
218
|
+
import { Linking } from 'react-native';
|
|
64
219
|
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
const subscription = Linking.addEventListener('url', ({ url }) => {
|
|
222
|
+
void v6.handleRedirectUrl(url);
|
|
223
|
+
});
|
|
69
224
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
225
|
+
return () => subscription.remove();
|
|
226
|
+
}, [v6.handleRedirectUrl]);
|
|
227
|
+
|
|
228
|
+
const openRedirect = async () => {
|
|
229
|
+
if (v6.state.prompt?.prompt.type !== 'redirect') {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
await Linking.openURL(v6.state.prompt.prompt.url);
|
|
234
|
+
};
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
React Native handles the JavaScript callback side, but you still need to register your
|
|
238
|
+
callback scheme natively on iOS and Android so the app receives the return URL.
|
|
239
|
+
|
|
240
|
+
## Backend Exchange
|
|
241
|
+
|
|
242
|
+
When the flow completes, the SDK returns:
|
|
243
|
+
|
|
244
|
+
- `session`
|
|
245
|
+
- `authCode`
|
|
246
|
+
- `expiresAt`
|
|
247
|
+
- `codeVerifier` when PKCE was generated by the SDK
|
|
248
|
+
- `traceId` for support and correlation
|
|
249
|
+
|
|
250
|
+
For most apps, send `authCode` and `codeVerifier` to your backend immediately over HTTPS
|
|
251
|
+
and perform the exchange there. Keep OAuth client credentials and token verification on
|
|
252
|
+
the server, not in the React Native app.
|
|
253
|
+
|
|
254
|
+
Recommended payload shape:
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"authCode": "<authCode>",
|
|
259
|
+
"codeVerifier": "<optional-codeVerifier>",
|
|
260
|
+
"identifier": "user@example.com",
|
|
261
|
+
"session": "<optional-session>"
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Your backend should:
|
|
266
|
+
|
|
267
|
+
1. exchange `authCode` and `codeVerifier` with the Hawcx backend SDK
|
|
268
|
+
2. verify the returned claims
|
|
269
|
+
3. create your app session or tokens
|
|
270
|
+
4. return the app auth result your app needs
|
|
271
|
+
|
|
272
|
+
### React Native app-to-backend example
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
import { useEffect } from 'react';
|
|
276
|
+
import {
|
|
277
|
+
storeBackendOAuthTokens,
|
|
278
|
+
useHawcxV6Auth,
|
|
279
|
+
} from '@hawcx/react-native-sdk';
|
|
280
|
+
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
if (v6.state.status !== 'completed' || !v6.state.completed) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
75
285
|
|
|
76
|
-
const
|
|
77
|
-
const response = await fetch('https://your-backend.example.com/api/hawcx/
|
|
286
|
+
const run = async () => {
|
|
287
|
+
const response = await fetch('https://your-backend.example.com/api/hawcx/exchange', {
|
|
78
288
|
method: 'POST',
|
|
79
289
|
headers: { 'Content-Type': 'application/json' },
|
|
80
|
-
body: JSON.stringify({
|
|
290
|
+
body: JSON.stringify({
|
|
291
|
+
authCode: v6.state.completed.authCode,
|
|
292
|
+
codeVerifier: v6.state.completed.codeVerifier,
|
|
293
|
+
identifier,
|
|
294
|
+
session: v6.state.completed.session,
|
|
295
|
+
}),
|
|
81
296
|
});
|
|
297
|
+
|
|
82
298
|
if (!response.ok) {
|
|
83
|
-
throw new Error('Backend
|
|
299
|
+
throw new Error('Backend exchange failed');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const result = await response.json();
|
|
303
|
+
|
|
304
|
+
if (result.accessToken) {
|
|
305
|
+
await storeBackendOAuthTokens(
|
|
306
|
+
identifier,
|
|
307
|
+
result.accessToken,
|
|
308
|
+
result.refreshToken,
|
|
309
|
+
);
|
|
84
310
|
}
|
|
85
|
-
const { access_token, refresh_token } = await response.json();
|
|
86
|
-
await storeBackendOAuthTokens(email.trim(), access_token, refresh_token);
|
|
87
311
|
};
|
|
88
312
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
{/* Collect identifier */}
|
|
92
|
-
<Button title="Continue" onPress={() => authenticate(email.trim())} />
|
|
93
|
-
|
|
94
|
-
{state.status === 'otp' && (
|
|
95
|
-
<>
|
|
96
|
-
<TextInput value={otp} onChangeText={setOtp} keyboardType="number-pad" />
|
|
97
|
-
<Button title="Verify OTP" onPress={() => submitOtp(otp)} />
|
|
98
|
-
</>
|
|
99
|
-
)}
|
|
100
|
-
|
|
101
|
-
{state.status === 'authorization_code' && <Text>Sending authorization code…</Text>}
|
|
102
|
-
{state.status === 'additional_verification_required' && (
|
|
103
|
-
<Text>Additional verification required: {state.payload.detail ?? state.payload.sessionId}</Text>
|
|
104
|
-
)}
|
|
105
|
-
{state.status === 'error' && <Text>{state.error.message}</Text>}
|
|
106
|
-
</>
|
|
107
|
-
);
|
|
108
|
-
}
|
|
313
|
+
void run();
|
|
314
|
+
}, [identifier, v6.state]);
|
|
109
315
|
```
|
|
110
316
|
|
|
111
|
-
|
|
317
|
+
`storeBackendOAuthTokens` is optional for the core V6 flow. Use it when your backend
|
|
318
|
+
returns tokens that the shared native session and push helpers should persist.
|
|
112
319
|
|
|
113
|
-
|
|
320
|
+
For backend implementation details, see:
|
|
114
321
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
import { exchangeCodeForTokenAndClaims } from '@hawcx/oauth-client';
|
|
322
|
+
- [Node.js backend quickstart](https://docs.hawcx.com/docs/v1/sdk-reference/backend/nodejs/quickstart)
|
|
323
|
+
- [Python backend quickstart](https://docs.hawcx.com/docs/v1/sdk-reference/backend/python/quickstart)
|
|
118
324
|
|
|
119
|
-
|
|
120
|
-
app.use(express.json());
|
|
325
|
+
## QR Approvals and Web Login Helpers
|
|
121
326
|
|
|
122
|
-
|
|
123
|
-
const { email, code, expires_in } = req.body ?? {};
|
|
124
|
-
if (!email || !code) {
|
|
125
|
-
return res.status(400).json({ success: false, error: 'Missing email or code' });
|
|
126
|
-
}
|
|
327
|
+
The package also exposes helpers for QR approval and legacy web-login scans:
|
|
127
328
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
oauthTokenUrl: process.env.HAWCX_OAUTH_TOKEN_ENDPOINT!,
|
|
132
|
-
clientId: process.env.HAWCX_OAUTH_CLIENT_ID!,
|
|
133
|
-
publicKey: process.env.HAWCX_OAUTH_PUBLIC_KEY_PEM!,
|
|
134
|
-
audience: process.env.HAWCX_OAUTH_CLIENT_ID,
|
|
135
|
-
issuer: process.env.HAWCX_OAUTH_ISSUER,
|
|
136
|
-
});
|
|
329
|
+
- `routeWebLoginScan(raw)`
|
|
330
|
+
- `approveV6Qr(rawPayload, identifier, options)`
|
|
331
|
+
- `useHawcxWebLogin()`
|
|
137
332
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
333
|
+
For protocol QR payloads, you can approve directly from React Native:
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
import { approveV6Qr, routeWebLoginScan } from '@hawcx/react-native-sdk';
|
|
337
|
+
|
|
338
|
+
const route = routeWebLoginScan(scanValue);
|
|
339
|
+
if (route.kind === 'protocol_qr') {
|
|
340
|
+
const result = await approveV6Qr(route.payload.raw, identifier, {
|
|
341
|
+
rememberDevice: true,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
console.log(result.outcome, result.payloadType);
|
|
345
|
+
}
|
|
148
346
|
```
|
|
149
347
|
|
|
150
|
-
|
|
348
|
+
## Existing V5 and Shared Helpers
|
|
349
|
+
|
|
350
|
+
The package still includes the older V5 auth surface for apps that already use it,
|
|
351
|
+
including:
|
|
151
352
|
|
|
152
|
-
|
|
353
|
+
- `authenticate`, `submitOtp`, `useHawcxAuth`
|
|
354
|
+
- `useHawcxWebLogin`
|
|
355
|
+
- `setPushDeviceToken`
|
|
356
|
+
- `notifyUserAuthenticated`
|
|
357
|
+
- `handlePushNotification`, `approvePushRequest`, `declinePushRequest`
|
|
153
358
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* `addAuthListener` / `addSessionListener` / `addPushListener` – Lower-level event APIs if you prefer an imperative approach.
|
|
157
|
-
* `setPushDeviceToken` / `notifyUserAuthenticated` – Wire push login approvals.
|
|
359
|
+
Shared helpers such as `initialize` and `storeBackendOAuthTokens` remain available across
|
|
360
|
+
the current package surface.
|
|
158
361
|
|
|
159
|
-
|
|
362
|
+
That makes incremental migration possible: new V6 flows can live on
|
|
363
|
+
`useHawcxV6Auth` while existing utilities remain available in the same package.
|
|
160
364
|
|
|
161
365
|
## Example App
|
|
162
366
|
|
|
163
|
-
|
|
367
|
+
The `example/` directory contains the in-repo React Native reference app used during SDK
|
|
368
|
+
development:
|
|
164
369
|
|
|
165
370
|
```bash
|
|
166
371
|
cd example
|
|
167
372
|
npm install
|
|
168
|
-
npm run ios
|
|
373
|
+
npm run ios
|
|
374
|
+
# or
|
|
375
|
+
npm run android
|
|
169
376
|
```
|
|
170
377
|
|
|
171
|
-
|
|
378
|
+
Use it to validate V6 auth flows against your environment before integrating into your
|
|
379
|
+
own app.
|
|
380
|
+
|
|
381
|
+
## Documentation
|
|
382
|
+
|
|
383
|
+
- [V6 React Native guide](https://docs.hawcx.com/docs/v1/sdk-reference/frontend/react-native/sdk-v6)
|
|
384
|
+
- [V5 React Native guide](https://docs.hawcx.com/docs/v1/sdk-reference/frontend/react-native/sdk)
|
|
385
|
+
- [V6 iOS guide](https://docs.hawcx.com/docs/v1/sdk-reference/frontend/ios/sdk-v6)
|
|
386
|
+
- [V6 Android guide](https://docs.hawcx.com/docs/v1/sdk-reference/frontend/android/sdk-v6)
|
|
387
|
+
- [Node.js backend quickstart](https://docs.hawcx.com/docs/v1/sdk-reference/backend/nodejs/quickstart)
|
|
388
|
+
- [Python backend quickstart](https://docs.hawcx.com/docs/v1/sdk-reference/backend/python/quickstart)
|
|
389
|
+
- [Documentation home](https://docs.hawcx.com)
|
|
172
390
|
|
|
173
391
|
## Support
|
|
174
392
|
|
|
175
|
-
|
|
176
|
-
|
|
393
|
+
- [Website](https://www.hawcx.com)
|
|
394
|
+
- [Support Email](mailto:info@hawcx.com)
|
package/android/build.gradle
CHANGED
|
@@ -22,7 +22,7 @@ def safeExtGet(prop, fallback) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
group = 'com.hawcx.reactnative'
|
|
25
|
-
version = project.findProperty('HAWCX_REACT_NATIVE_ANDROID_VERSION') ?: '1.0
|
|
25
|
+
version = project.findProperty('HAWCX_REACT_NATIVE_ANDROID_VERSION') ?: '1.1.0'
|
|
26
26
|
|
|
27
27
|
repositories {
|
|
28
28
|
mavenCentral()
|
|
@@ -124,7 +124,7 @@ afterEvaluate {
|
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
dependencies {
|
|
127
|
-
api("api.hawcx:hawcx:
|
|
127
|
+
api("api.hawcx:hawcx:6.0.2")
|
|
128
128
|
def reactNativeVersion = safeExtGet('reactNativeAndroidVersion', '0.73.9')
|
|
129
129
|
implementation "com.facebook.react:react-android:$reactNativeVersion"
|
|
130
130
|
implementation 'androidx.annotation:annotation:1.8.1'
|
|
@@ -21,6 +21,10 @@ internal class HawcxEventDispatcher(
|
|
|
21
21
|
emitEvent(PUSH_EVENT_NAME, type, payload)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
fun emitV6FlowEvent(type: String, payload: WritableMap? = null) {
|
|
25
|
+
emitEvent(V6_FLOW_EVENT_NAME, type, payload)
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
private fun emitEvent(eventName: String, type: String, payload: WritableMap?) {
|
|
25
29
|
val map = Arguments.createMap().apply {
|
|
26
30
|
putString("type", type)
|