@criipto/verify-react 5.0.2 → 6.0.1
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 +152 -32
- package/dist/index.d.ts +44 -31
- package/dist/index.js +38 -118
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
# @criipto/verify-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Idura Verify React SDK lets you authenticate users with European eID providers [supported by Idura](https://docs.idura.app/verify/e-ids/).
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`@criipto/verify-react` supports app switching for Swedish BankID and Danish MitID by a best-effort mobile-os detection and setting the relevant Criipto Verify login hints.
|
|
5
|
+
The SDK uses the [PKCE flow](https://docs.idura.app/verify/reference/authorization-flows/pkce/) suitable for public clients.
|
|
8
6
|
|
|
9
7
|
## Installation
|
|
10
8
|
|
|
11
|
-
Using [npm](https://npmjs.org/)
|
|
12
|
-
|
|
13
9
|
```sh
|
|
14
10
|
npm install @criipto/verify-react
|
|
15
11
|
```
|
|
16
12
|
|
|
17
|
-
##
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
You need an Idura application to initialize the SDK. If you haven't already, follow the [dashboard setup guide](https://docs.idura.app/verify/getting-started/dashboard-setup/) to create one.
|
|
16
|
+
|
|
17
|
+
The SDK needs two values from your Idura application:
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
- your Idura domain
|
|
20
|
+
- your application client ID
|
|
21
|
+
|
|
22
|
+
## Initialize the SDK
|
|
23
|
+
|
|
24
|
+
Initialize the SDK by wrapping your React app in `CriiptoVerifyProvider`:
|
|
20
25
|
|
|
21
26
|
```jsx
|
|
22
27
|
// src/index.js
|
|
@@ -28,8 +33,8 @@ import App from './App';
|
|
|
28
33
|
|
|
29
34
|
ReactDOM.render(
|
|
30
35
|
<CriiptoVerifyProvider
|
|
31
|
-
domain="{
|
|
32
|
-
clientID="{
|
|
36
|
+
domain="{YOUR_IDURA_DOMAIN}"
|
|
37
|
+
clientID="{YOUR_IDURA_APPLICATION_CLIENT_ID}"
|
|
33
38
|
redirectUri={window.location.href}
|
|
34
39
|
>
|
|
35
40
|
<App />
|
|
@@ -38,15 +43,43 @@ ReactDOM.render(
|
|
|
38
43
|
);
|
|
39
44
|
```
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
The `redirectUri` you pass to `CriiptoVerifyProvider` is where Idura returns the user after login, and it must be registered as a redirect URL on your Idura application. The examples use `window.location.href`, but any route (e.g. a dedicated `/callback` path) works too.
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
## Call the `useCriiptoVerify` hook
|
|
49
|
+
|
|
50
|
+
Inside a component wrapped by `CriiptoVerifyProvider`, call `useCriiptoVerify` to read the auth state and start a login.
|
|
51
|
+
|
|
52
|
+
```jsx
|
|
53
|
+
const {
|
|
54
|
+
result,
|
|
55
|
+
claims,
|
|
56
|
+
error,
|
|
57
|
+
loginWithRedirect,
|
|
58
|
+
loginWithPopup,
|
|
59
|
+
logout,
|
|
60
|
+
isLoading,
|
|
61
|
+
isInitializing,
|
|
62
|
+
} = useCriiptoVerify();
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- `result`: the login outcome, `result.id_token` or `result.code` on success and an error otherwise
|
|
66
|
+
- `claims`: the decoded `id_token`
|
|
67
|
+
- `error`: configuration and login errors
|
|
68
|
+
- `loginWithRedirect` / `loginWithPopup`: start a login with redirect or in a popup window
|
|
69
|
+
- `logout`: clear the session store and end the SSO session
|
|
70
|
+
- `isLoading` / `isInitializing`: whether the SDK is still working or starting up
|
|
71
|
+
|
|
72
|
+
## Render login options
|
|
73
|
+
|
|
74
|
+
The SDK provides an `AuthMethodSelector` component that renders a method selector screen where your users can choose a login method.
|
|
75
|
+
|
|
76
|
+
By default, `AuthMethodSelector` shows one button per eID method enabled for your Idura application (**Applications → your app → eIDs** in the dashboard).
|
|
44
77
|
|
|
45
78
|
```jsx
|
|
46
79
|
// src/App.js
|
|
47
80
|
import React from 'react';
|
|
48
81
|
import { useCriiptoVerify, AuthMethodSelector } from '@criipto/verify-react';
|
|
49
|
-
import '@criipto/verify-react/index.css';
|
|
82
|
+
import '@criipto/verify-react/index.css'; // Import the stylesheet, or the buttons render unstyled.
|
|
50
83
|
|
|
51
84
|
export default function App() {
|
|
52
85
|
const { result, error } = useCriiptoVerify();
|
|
@@ -64,20 +97,87 @@ export default function App() {
|
|
|
64
97
|
}
|
|
65
98
|
```
|
|
66
99
|
|
|
67
|
-
Always render the `error` field from `useCriiptoVerify`. It surfaces both **configuration errors** (e.g. invalid `domain` or `clientID`, or CORS) raised when the provider mounts, and **runtime errors** raised during a login attempt (e.g. user cancellation, OAuth2 errors from the IdP). Without rendering `error`, misconfiguration and failed logins will appear silent to the user.
|
|
100
|
+
Always render the `error` field from `useCriiptoVerify`. It surfaces both **configuration errors** (e.g. invalid `domain` or `clientID`, or CORS) raised when the provider mounts, and **runtime errors** raised during a login attempt (e.g. user cancellation, or OAuth2 errors from the [identity provider (IdP)](https://docs.idura.app/verify/reference/glossary/#identity-provider-idp)). Without rendering `error`, misconfiguration and failed logins will appear silent to the user.
|
|
101
|
+
|
|
102
|
+
### Select eIDs programmatically
|
|
103
|
+
|
|
104
|
+
To control eID methods from your code instead of the dashboard, pass `acrValues` to `AuthMethodSelector`:
|
|
105
|
+
|
|
106
|
+
```jsx
|
|
107
|
+
<AuthMethodSelector
|
|
108
|
+
acrValues={['urn:grn:authn:dk:mitid:substantial', 'urn:grn:authn:dk:mitid:high']}
|
|
109
|
+
/>
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
See the [Authorize URL Builder](https://docs.idura.app/verify/guides/authorize-url-builder) or individual eID pages for the full list of supported `acr_values`.
|
|
113
|
+
|
|
114
|
+
### Configure the request per eID
|
|
115
|
+
|
|
116
|
+
`login_hint` and `scope` values are eID specific, so a single provider-level setting rarely fits every button. Pass a `beforeAuthorize` function to `CriiptoVerifyProvider` to adjust the request for the eID the user actually picked:
|
|
117
|
+
|
|
118
|
+
```jsx
|
|
119
|
+
<CriiptoVerifyProvider
|
|
120
|
+
domain="{YOUR_IDURA_DOMAIN}"
|
|
121
|
+
clientID="{YOUR_IDURA_APPLICATION_CLIENT_ID}"
|
|
122
|
+
beforeAuthorize={({ acrValues }) => {
|
|
123
|
+
if (acrValues[0].startsWith('urn:grn:authn:dk:mitid')) {
|
|
124
|
+
return { scope: 'openid address' };
|
|
125
|
+
}
|
|
126
|
+
if (acrValues[0].startsWith('urn:grn:authn:se:bankid')) {
|
|
127
|
+
return { loginHint: 'stepUp:mrtd' };
|
|
128
|
+
}
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<App />
|
|
132
|
+
</CriiptoVerifyProvider>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`beforeAuthorize` runs just before every authorize request is built, whichever way the login was started: `AuthMethodSelector`, `AuthMethodButton`, `SEBankIDQRCode`, `loginWithRedirect` or `loginWithPopup`. Return the values you want to change for that one request, or nothing at all to leave it as configured on the provider.
|
|
136
|
+
|
|
137
|
+
- `acrValues` is always an array, and holds a single value for logins started from a button or `AuthMethodSelector`
|
|
138
|
+
- `options` holds the request as the SDK would otherwise send it, in case you want to inspect it
|
|
139
|
+
- you can override `loginHint`, `scope`, `prompt`, `uiLocales`, `state`, `nonce`, `extraUrlParams` and the `action`/`message` shorthands
|
|
140
|
+
- `loginHint` is appended to the hints the SDK already adds, so use `action` and `message` rather than writing `action:`/`message:` hints yourself
|
|
141
|
+
- `acrValues`, `redirectUri` and the PKCE and response parameters are managed by the SDK and cannot be overridden here. Use `redirectUri` on the button or selector to change where a single eID returns the user
|
|
142
|
+
|
|
143
|
+
The hint and scope values differ per eID, see the individual eID pages in the [Idura docs](https://docs.idura.app/verify/e-ids/) for what each one supports.
|
|
144
|
+
|
|
145
|
+
## Send the user directly to an eID login screen
|
|
146
|
+
|
|
147
|
+
If you don't need the method selector, use `loginWithRedirect` (or `loginWithPopup`) and pass a single eID method identifier in `acrValues`.
|
|
148
|
+
|
|
149
|
+
```jsx
|
|
150
|
+
// src/App.js
|
|
151
|
+
import React from 'react';
|
|
152
|
+
import { useCriiptoVerify } from '@criipto/verify-react';
|
|
153
|
+
|
|
154
|
+
export default function App() {
|
|
155
|
+
const { result, loginWithRedirect } = useCriiptoVerify();
|
|
156
|
+
|
|
157
|
+
if (result?.id_token) {
|
|
158
|
+
return <pre>{JSON.stringify(result.id_token, null, 2)}</pre>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<button onClick={() => loginWithRedirect({ acrValues: 'urn:grn:authn:dk:mitid:substantial' })}>
|
|
163
|
+
Log in with MitID
|
|
164
|
+
</button>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
```
|
|
68
168
|
|
|
69
169
|
## CORS
|
|
70
170
|
|
|
71
|
-
The
|
|
171
|
+
The SDK makes fetch requests to Idura for two reasons:
|
|
72
172
|
|
|
73
173
|
1. To load application configuration when the provider mounts.
|
|
74
174
|
2. To push the authorization request (PAR) when a user clicks a login button.
|
|
75
175
|
|
|
76
|
-
Make sure
|
|
176
|
+
Make sure the origin your React app runs on is included in the list of redirect URLs for your Idura application. Otherwise, both calls will fail with CORS errors.
|
|
77
177
|
|
|
78
178
|
## Sessions
|
|
79
179
|
|
|
80
|
-
If you want to use
|
|
180
|
+
If you want to use the SDK for session management (rather than one-off authentication), you can configure a `sessionStore`:
|
|
81
181
|
|
|
82
182
|
```jsx
|
|
83
183
|
// src/index.js
|
|
@@ -89,8 +189,8 @@ import App from './App';
|
|
|
89
189
|
|
|
90
190
|
ReactDOM.render(
|
|
91
191
|
<CriiptoVerifyProvider
|
|
92
|
-
domain="{
|
|
93
|
-
clientID="{
|
|
192
|
+
domain="{YOUR_IDURA_DOMAIN}"
|
|
193
|
+
clientID="{YOUR_IDURA_APPLICATION_CLIENT_ID}"
|
|
94
194
|
redirectUri={window.location.href}
|
|
95
195
|
sessionStore={window.sessionStorage} // or window.localStorage
|
|
96
196
|
>
|
|
@@ -100,11 +200,11 @@ ReactDOM.render(
|
|
|
100
200
|
);
|
|
101
201
|
```
|
|
102
202
|
|
|
103
|
-
When a `sessionStore` is configured the
|
|
203
|
+
When a `sessionStore` is configured, the SDK stores the `id_token` in your chosen storage (`sessionStorage` or `localStorage`) and invalidates it once it expires.
|
|
104
204
|
|
|
105
|
-
The
|
|
205
|
+
The SDK will also attempt to retrieve the token on page load via SSO. (This requires SSO enabled on your Idura domain: check **Domains → your domain → SSO** section in the dashboard).
|
|
106
206
|
|
|
107
|
-
|
|
207
|
+
For longer sessions, you can increase the **Token lifetime** setting of your Idura application (**Applications → your app → Advanced Options**).
|
|
108
208
|
|
|
109
209
|
```jsx
|
|
110
210
|
// src/App.js
|
|
@@ -126,7 +226,7 @@ export default function App() {
|
|
|
126
226
|
<React.Fragment>
|
|
127
227
|
{error ? (
|
|
128
228
|
<p>
|
|
129
|
-
An error
|
|
229
|
+
An error occurred:{' '}
|
|
130
230
|
{error instanceof OAuth2Error
|
|
131
231
|
? `${error.error} (${error.error_description})`
|
|
132
232
|
: String(error)}
|
|
@@ -139,18 +239,34 @@ export default function App() {
|
|
|
139
239
|
}
|
|
140
240
|
```
|
|
141
241
|
|
|
142
|
-
### Logging
|
|
242
|
+
### Logging out
|
|
143
243
|
|
|
144
|
-
|
|
244
|
+
The `logout` method clears the session store and ends any existing SSO session.
|
|
145
245
|
|
|
146
246
|
```jsx
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
247
|
+
// src/App.js
|
|
248
|
+
import React from 'react';
|
|
249
|
+
import { useCriiptoVerify, AuthMethodSelector } from '@criipto/verify-react';
|
|
250
|
+
import '@criipto/verify-react/index.css';
|
|
251
|
+
|
|
252
|
+
export default function App() {
|
|
253
|
+
const { claims, logout } = useCriiptoVerify();
|
|
254
|
+
|
|
255
|
+
if (claims) {
|
|
256
|
+
return (
|
|
257
|
+
<React.Fragment>
|
|
258
|
+
<pre>{JSON.stringify(claims, null, 2)}</pre>
|
|
259
|
+
<button onClick={() => logout({ redirectUri: window.location.href })}>Log out</button>
|
|
260
|
+
</React.Fragment>
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return <AuthMethodSelector />;
|
|
265
|
+
}
|
|
152
266
|
```
|
|
153
267
|
|
|
268
|
+
`logout` takes an optional `redirectUri` (where to send the user afterwards) and `state` (an opaque string used to mitigate CSRF attacks, see [state](https://docs.idura.app/verify/reference/request-parameters/#state)).
|
|
269
|
+
|
|
154
270
|
## useEffect + loginWithRedirect
|
|
155
271
|
|
|
156
272
|
If you are triggering `loginWithRedirect` inside a `useEffect` hook, you need to allow the SDK time to initialize a few values before you redirect the user:
|
|
@@ -164,6 +280,10 @@ useEffect(() => {
|
|
|
164
280
|
}, [isLoading, isInitializing]);
|
|
165
281
|
```
|
|
166
282
|
|
|
167
|
-
##
|
|
283
|
+
## Idura
|
|
284
|
+
|
|
285
|
+
Learn more about Idura and sign up for a free developer account at [idura.eu](https://idura.eu).
|
|
286
|
+
|
|
287
|
+
### Why the package is named `@criipto/verify-react`
|
|
168
288
|
|
|
169
|
-
|
|
289
|
+
Idura was previously called Criipto, and most of our SDKs keep the `@criipto` name for backwards compatibility. You can read more about the rebrand in [our blog](https://idura.eu/blog/criipto-is-now-idura).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import * as _criipto_auth_js0 from "@criipto/auth-js";
|
|
3
|
-
import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1, PKCEPublicPart, Prompt, ResponseType } from "@criipto/auth-js";
|
|
3
|
+
import CriiptoAuth, { AuthorizeUrlParamsOptional, OAuth2Error, OAuth2Error as OAuth2Error$1, PKCEPublicPart, Prompt, ResponseType } from "@criipto/auth-js";
|
|
4
4
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
//#region src/context.d.ts
|
|
7
|
-
type ResultSource = '
|
|
7
|
+
type ResultSource = 'SEBankIDQrCode' | 'SEBankIDSameDeviceButton' | 'redirect' | 'popup';
|
|
8
8
|
type Result = {
|
|
9
9
|
id_token: string;
|
|
10
10
|
state?: string;
|
|
@@ -26,6 +26,39 @@ type Claims = {
|
|
|
26
26
|
exp: number;
|
|
27
27
|
[key: string]: string | number;
|
|
28
28
|
};
|
|
29
|
+
interface BeforeAuthorizeParams {
|
|
30
|
+
/**
|
|
31
|
+
* The acr_values of the authorize request that is about to be made, always normalized to an array.
|
|
32
|
+
* For logins started from a button or `AuthMethodSelector` this will hold exactly one value.
|
|
33
|
+
*/
|
|
34
|
+
acrValues: string[];
|
|
35
|
+
/**
|
|
36
|
+
* The parameters the SDK is about to use, with `CriiptoVerifyProvider` configuration already applied.
|
|
37
|
+
*/
|
|
38
|
+
options: AuthorizeUrlParamsOptional;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parameters to override for a single authorize request. Any field left out (or set to `undefined`)
|
|
42
|
+
* keeps the value configured on `CriiptoVerifyProvider`.
|
|
43
|
+
*/
|
|
44
|
+
interface BeforeAuthorizeOverrides {
|
|
45
|
+
/**
|
|
46
|
+
* Appended to the login_hint of this request, just like a `loginHint` passed directly to
|
|
47
|
+
* `loginWithRedirect`. Use `action` and `message` rather than `action:`/`message:` hints,
|
|
48
|
+
* as those are managed by the SDK.
|
|
49
|
+
*/
|
|
50
|
+
loginHint?: string;
|
|
51
|
+
action?: Action;
|
|
52
|
+
message?: string;
|
|
53
|
+
scope?: string;
|
|
54
|
+
prompt?: Prompt;
|
|
55
|
+
uiLocales?: string;
|
|
56
|
+
state?: string;
|
|
57
|
+
nonce?: string;
|
|
58
|
+
extraUrlParams?: {
|
|
59
|
+
[key: string]: string | null;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
29
62
|
//#endregion
|
|
30
63
|
//#region src/provider.d.ts
|
|
31
64
|
interface CriiptoVerifyProviderOptions {
|
|
@@ -67,6 +100,14 @@ interface CriiptoVerifyProviderOptions {
|
|
|
67
100
|
*/
|
|
68
101
|
response?: 'token' | 'code';
|
|
69
102
|
completionStrategy?: 'client' | 'openidprovider';
|
|
103
|
+
/**
|
|
104
|
+
* Called just before each authorize request is built, for every login flow
|
|
105
|
+
* (`AuthMethodSelector`, `AuthMethodButton`, `SEBankIDQRCode`, `loginWithRedirect` and `loginWithPopup`).
|
|
106
|
+
* Return the parameters you wish to change for that particular request, for instance a
|
|
107
|
+
* `loginHint` that depends on the acr_value the user picked. Returning nothing leaves the
|
|
108
|
+
* request as configured on the provider.
|
|
109
|
+
*/
|
|
110
|
+
beforeAuthorize?: (params: BeforeAuthorizeParams) => BeforeAuthorizeOverrides | void;
|
|
70
111
|
/**
|
|
71
112
|
* @deprecated Criipto internal use
|
|
72
113
|
*/
|
|
@@ -159,34 +200,6 @@ declare function AuthButtonGroup(props: {
|
|
|
159
200
|
children: React.ReactNode;
|
|
160
201
|
}): react_jsx_runtime0.JSX.Element;
|
|
161
202
|
//#endregion
|
|
162
|
-
//#region src/components/QRCode.d.ts
|
|
163
|
-
declare const QRCode: React.FC<{
|
|
164
|
-
margin?: number;
|
|
165
|
-
className?: string;
|
|
166
|
-
acrValues?: string[];
|
|
167
|
-
children: (props: {
|
|
168
|
-
qrElement: React.ReactElement;
|
|
169
|
-
/**
|
|
170
|
-
* Will be true once the QR code has been scanned
|
|
171
|
-
*/
|
|
172
|
-
isAcknowledged: boolean;
|
|
173
|
-
/**
|
|
174
|
-
* Will be true if the user cancels the login on his mobile device
|
|
175
|
-
*/
|
|
176
|
-
isCancelled: boolean;
|
|
177
|
-
/**
|
|
178
|
-
* Whether or not QR codes are enabled for this Criipto Applicaiton
|
|
179
|
-
*/
|
|
180
|
-
isEnabled: boolean | undefined;
|
|
181
|
-
error: OAuth2Error$1 | Error | null;
|
|
182
|
-
retry: () => void;
|
|
183
|
-
/**
|
|
184
|
-
* A method for triggering a full screen redirect to authentication (useful if user is on mobile device already)
|
|
185
|
-
*/
|
|
186
|
-
redirect: () => Promise<void>;
|
|
187
|
-
}) => React.ReactElement;
|
|
188
|
-
}>;
|
|
189
|
-
//#endregion
|
|
190
203
|
//#region src/components/SEBankIDQRCode.d.ts
|
|
191
204
|
interface Props {
|
|
192
205
|
redirectUri?: string;
|
|
@@ -263,5 +276,5 @@ declare function useCriiptoVerify(): {
|
|
|
263
276
|
//#region src/utils.d.ts
|
|
264
277
|
declare function filterAcrValues(input: string[]): string[];
|
|
265
278
|
//#endregion
|
|
266
|
-
export { type Action, AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, type Language, OAuth2Error,
|
|
279
|
+
export { type Action, AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, type BeforeAuthorizeOverrides, type BeforeAuthorizeParams, CriiptoVerifyProvider, type Language, OAuth2Error, type Result, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
|
|
267
280
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import React, { createContext, useCallback, useContext, useEffect,
|
|
2
|
-
import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1,
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1, clearPKCEState, generatePKCE, parseAuthorizeResponseFromLocation, savePKCEState } from "@criipto/auth-js";
|
|
3
3
|
import jwtDecode from "jwt-decode";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import { UAParser } from "@ua-parser-js/pro-enterprise";
|
|
6
|
-
import QRCode
|
|
6
|
+
import QRCode from "qrcode";
|
|
7
7
|
import classNames from "classnames";
|
|
8
8
|
//#region src/context.ts
|
|
9
9
|
const actions = [
|
|
@@ -45,7 +45,7 @@ const CriiptoVerifyContext = createContext({
|
|
|
45
45
|
});
|
|
46
46
|
//#endregion
|
|
47
47
|
//#region package.json
|
|
48
|
-
var version = "
|
|
48
|
+
var version = "6.0.1";
|
|
49
49
|
//#endregion
|
|
50
50
|
//#region src/i18n/en.ts
|
|
51
51
|
const en = {
|
|
@@ -464,10 +464,14 @@ const MESSAGE_SUPPORTING_ACR_VALUES = [
|
|
|
464
464
|
"urn:grn:authn:se:bankid:same-device",
|
|
465
465
|
"urn:grn:authn:se:bankid:another-device:qr"
|
|
466
466
|
];
|
|
467
|
+
function normalizeAcrValues(acrValues) {
|
|
468
|
+
if (!acrValues) return [];
|
|
469
|
+
return Array.isArray(acrValues) ? acrValues : [acrValues];
|
|
470
|
+
}
|
|
467
471
|
function buildLoginHint(loginHint, params) {
|
|
468
|
-
const { options, action, message } = params;
|
|
469
|
-
const acrValues = (options === null || options === void 0 ? void 0 : options.acrValues)
|
|
470
|
-
let hints = (loginHint ? loginHint.split(" ") : []).concat((options === null || options === void 0 ? void 0 : options.loginHint) ? options === null || options === void 0 ? void 0 : options.loginHint.split(" ") : []).filter((hint) => !hint.startsWith("message:") && !hint.startsWith("action:"));
|
|
472
|
+
const { options, action, message, extraLoginHint } = params;
|
|
473
|
+
const acrValues = normalizeAcrValues(options === null || options === void 0 ? void 0 : options.acrValues);
|
|
474
|
+
let hints = (loginHint ? loginHint.split(" ") : []).concat((options === null || options === void 0 ? void 0 : options.loginHint) ? options === null || options === void 0 ? void 0 : options.loginHint.split(" ") : []).concat(extraLoginHint ? extraLoginHint.split(" ") : []).filter((hint) => !hint.startsWith("message:") && !hint.startsWith("action:"));
|
|
471
475
|
if (action) {
|
|
472
476
|
hints = hints.filter((h) => !h.startsWith("action:"));
|
|
473
477
|
if (acrValues.length === 1) {
|
|
@@ -574,6 +578,10 @@ const CriiptoVerifyProvider = (props) => {
|
|
|
574
578
|
const action = (_ref = (_props$action = props.action) !== null && _props$action !== void 0 ? _props$action : parseAction(loginHint)) !== null && _ref !== void 0 ? _ref : "login";
|
|
575
579
|
const message = (_props$message = props.message) !== null && _props$message !== void 0 ? _props$message : parseMessage(loginHint);
|
|
576
580
|
const sessionStore = props.sessionStore;
|
|
581
|
+
const beforeAuthorizeRef = useRef(props.beforeAuthorize);
|
|
582
|
+
useEffect(() => {
|
|
583
|
+
beforeAuthorizeRef.current = props.beforeAuthorize;
|
|
584
|
+
}, [props.beforeAuthorize]);
|
|
577
585
|
const refreshPKCE = function() {
|
|
578
586
|
var _ref2 = _asyncToGenerator(function* () {
|
|
579
587
|
if (props.pkce) return props.pkce;
|
|
@@ -592,8 +600,8 @@ const CriiptoVerifyProvider = (props) => {
|
|
|
592
600
|
};
|
|
593
601
|
}();
|
|
594
602
|
const buildOptions = useCallback((options) => {
|
|
595
|
-
var _props$responseType, _props$state, _props$nonce, _props$prompt, _props$scope, _options$pkce;
|
|
596
|
-
|
|
603
|
+
var _props$responseType, _props$state, _props$nonce, _props$prompt, _props$scope, _options$pkce, _beforeAuthorizeRef$c, _overrides$state, _overrides$nonce, _overrides$prompt, _overrides$scope, _overrides$uiLocales, _overrides$action, _overrides$message;
|
|
604
|
+
const resolved = _objectSpread2(_objectSpread2({
|
|
597
605
|
redirectUri: defaultRedirectUri(props.redirectUri),
|
|
598
606
|
responseType: (_props$responseType = props.responseType) !== null && _props$responseType !== void 0 ? _props$responseType : "code",
|
|
599
607
|
responseMode: props.responseMode
|
|
@@ -611,6 +619,25 @@ const CriiptoVerifyProvider = (props) => {
|
|
|
611
619
|
}),
|
|
612
620
|
extraUrlParams: props.criiptoSdk !== void 0 ? { criipto_sdk: props.criiptoSdk } : { criipto_sdk: `@criipto/verify-react@${version}` }
|
|
613
621
|
});
|
|
622
|
+
const overrides = (_beforeAuthorizeRef$c = beforeAuthorizeRef.current) === null || _beforeAuthorizeRef$c === void 0 ? void 0 : _beforeAuthorizeRef$c.call(beforeAuthorizeRef, {
|
|
623
|
+
acrValues: normalizeAcrValues(resolved.acrValues),
|
|
624
|
+
options: resolved
|
|
625
|
+
});
|
|
626
|
+
if (!overrides) return resolved;
|
|
627
|
+
return _objectSpread2(_objectSpread2({}, resolved), {}, {
|
|
628
|
+
state: (_overrides$state = overrides.state) !== null && _overrides$state !== void 0 ? _overrides$state : resolved.state,
|
|
629
|
+
nonce: (_overrides$nonce = overrides.nonce) !== null && _overrides$nonce !== void 0 ? _overrides$nonce : resolved.nonce,
|
|
630
|
+
prompt: (_overrides$prompt = overrides.prompt) !== null && _overrides$prompt !== void 0 ? _overrides$prompt : resolved.prompt,
|
|
631
|
+
scope: (_overrides$scope = overrides.scope) !== null && _overrides$scope !== void 0 ? _overrides$scope : resolved.scope,
|
|
632
|
+
uiLocales: (_overrides$uiLocales = overrides.uiLocales) !== null && _overrides$uiLocales !== void 0 ? _overrides$uiLocales : resolved.uiLocales,
|
|
633
|
+
loginHint: buildLoginHint(props.loginHint, {
|
|
634
|
+
options,
|
|
635
|
+
action: (_overrides$action = overrides.action) !== null && _overrides$action !== void 0 ? _overrides$action : action,
|
|
636
|
+
message: (_overrides$message = overrides.message) !== null && _overrides$message !== void 0 ? _overrides$message : message,
|
|
637
|
+
extraLoginHint: overrides.loginHint
|
|
638
|
+
}),
|
|
639
|
+
extraUrlParams: _objectSpread2(_objectSpread2({}, resolved.extraUrlParams), overrides.extraUrlParams)
|
|
640
|
+
});
|
|
614
641
|
}, [
|
|
615
642
|
pkce,
|
|
616
643
|
props.state,
|
|
@@ -1215,7 +1242,7 @@ function useDraw(qrCode, options) {
|
|
|
1215
1242
|
if (!qrCode) return;
|
|
1216
1243
|
let isSubscribed = true;
|
|
1217
1244
|
_asyncToGenerator(function* () {
|
|
1218
|
-
const qrImage = yield QRCode
|
|
1245
|
+
const qrImage = yield QRCode.toDataURL(qrCode, {
|
|
1219
1246
|
errorCorrectionLevel: "low",
|
|
1220
1247
|
scale: 10,
|
|
1221
1248
|
width,
|
|
@@ -1819,113 +1846,6 @@ function Sweden(props) {
|
|
|
1819
1846
|
});
|
|
1820
1847
|
}
|
|
1821
1848
|
//#endregion
|
|
1822
|
-
//#region src/components/QRCode.tsx
|
|
1823
|
-
const QRCode = (props) => {
|
|
1824
|
-
var _ref, _props$acrValues;
|
|
1825
|
-
const { children, margin, className } = props;
|
|
1826
|
-
const elementRef = useRef(null);
|
|
1827
|
-
const { client, buildOptions, buildAuthorizeUrl, handleResponse, pkce, store, acrValues: configurationAcrValues } = useContext(CriiptoVerifyContext);
|
|
1828
|
-
const [requestId, setRequestId] = useState(() => Math.random().toString());
|
|
1829
|
-
const [isAcknowledged, setAcknowledged] = useState(false);
|
|
1830
|
-
const [isCancelled, setCancelled] = useState(false);
|
|
1831
|
-
const [error, setError] = useState(null);
|
|
1832
|
-
const [criiptoConfiguration, setCriiptoConfiguration] = useState(null);
|
|
1833
|
-
const isEnabled = criiptoConfiguration === null || criiptoConfiguration === void 0 ? void 0 : criiptoConfiguration.client.qr_enabled;
|
|
1834
|
-
const acrValues = (_ref = (_props$acrValues = props.acrValues) !== null && _props$acrValues !== void 0 ? _props$acrValues : configurationAcrValues) !== null && _ref !== void 0 ? _ref : [];
|
|
1835
|
-
useEffect(() => {
|
|
1836
|
-
let isSubsribed = true;
|
|
1837
|
-
client.fetchCriiptoConfiguration().then((c) => {
|
|
1838
|
-
if (!isSubsribed) return;
|
|
1839
|
-
setCriiptoConfiguration(c);
|
|
1840
|
-
});
|
|
1841
|
-
return () => {
|
|
1842
|
-
isSubsribed = false;
|
|
1843
|
-
};
|
|
1844
|
-
}, [client]);
|
|
1845
|
-
const redirect = useCallback(_asyncToGenerator(function* () {
|
|
1846
|
-
var _criiptoConfiguration;
|
|
1847
|
-
if (!criiptoConfiguration) return;
|
|
1848
|
-
const intermediaryUrl = ((_criiptoConfiguration = criiptoConfiguration.client.qr_intermediary_url) !== null && _criiptoConfiguration !== void 0 ? _criiptoConfiguration : criiptoConfiguration.qr_intermediary_url).replace("/{id}", "").replace("{id}", "");
|
|
1849
|
-
const authorizeUrl = new URL(yield buildAuthorizeUrl({ acrValues }));
|
|
1850
|
-
const authorizeParams = new URLSearchParams(authorizeUrl.search);
|
|
1851
|
-
authorizeParams.set("domain", authorizeUrl.host);
|
|
1852
|
-
authorizeUrl.host = new URL(intermediaryUrl).host;
|
|
1853
|
-
authorizeUrl.port = new URL(intermediaryUrl).port;
|
|
1854
|
-
authorizeUrl.pathname = new URL(intermediaryUrl).pathname + "/authorize";
|
|
1855
|
-
authorizeUrl.search = authorizeParams.toString();
|
|
1856
|
-
if (pkce && "code_verifier" in pkce) savePKCEState(store, {
|
|
1857
|
-
response_type: "id_token",
|
|
1858
|
-
pkce_code_verifier: pkce.code_verifier,
|
|
1859
|
-
redirect_uri: authorizeParams.get("redirect_uri")
|
|
1860
|
-
});
|
|
1861
|
-
window.location.href = authorizeUrl.toString();
|
|
1862
|
-
}), [
|
|
1863
|
-
buildAuthorizeUrl,
|
|
1864
|
-
criiptoConfiguration,
|
|
1865
|
-
acrValues
|
|
1866
|
-
]);
|
|
1867
|
-
const authorize = useCallback(() => {
|
|
1868
|
-
return client.qr.authorize(elementRef.current, _objectSpread2(_objectSpread2({}, buildOptions({ acrValues })), {}, { margin }));
|
|
1869
|
-
}, [
|
|
1870
|
-
client,
|
|
1871
|
-
buildOptions,
|
|
1872
|
-
margin,
|
|
1873
|
-
acrValues
|
|
1874
|
-
]);
|
|
1875
|
-
useLayoutEffect(() => {
|
|
1876
|
-
if (!elementRef.current) return;
|
|
1877
|
-
if (error) return;
|
|
1878
|
-
if (!isEnabled) return;
|
|
1879
|
-
const promise = authorize();
|
|
1880
|
-
promise.onAcknowledged = () => {
|
|
1881
|
-
setAcknowledged(true);
|
|
1882
|
-
};
|
|
1883
|
-
promise.then((response) => {
|
|
1884
|
-
if (promise.cancelled) return;
|
|
1885
|
-
handleResponse(response, {
|
|
1886
|
-
pkce: pkce && "code_verifier" in pkce ? pkce : void 0,
|
|
1887
|
-
source: "QRCode"
|
|
1888
|
-
});
|
|
1889
|
-
}).catch((err) => {
|
|
1890
|
-
if (err instanceof UserCancelledError) {
|
|
1891
|
-
setCancelled(true);
|
|
1892
|
-
return;
|
|
1893
|
-
}
|
|
1894
|
-
if (promise.cancelled) return;
|
|
1895
|
-
setError(err);
|
|
1896
|
-
handleResponse(err, { source: "QRCode" });
|
|
1897
|
-
});
|
|
1898
|
-
return () => {
|
|
1899
|
-
promise.cancel();
|
|
1900
|
-
};
|
|
1901
|
-
}, [
|
|
1902
|
-
authorize,
|
|
1903
|
-
pkce,
|
|
1904
|
-
handleResponse,
|
|
1905
|
-
requestId,
|
|
1906
|
-
error,
|
|
1907
|
-
isEnabled
|
|
1908
|
-
]);
|
|
1909
|
-
const handleRetry = () => {
|
|
1910
|
-
setAcknowledged(false);
|
|
1911
|
-
setCancelled(false);
|
|
1912
|
-
setError(null);
|
|
1913
|
-
setRequestId(Math.random().toString());
|
|
1914
|
-
};
|
|
1915
|
-
return children({
|
|
1916
|
-
qrElement: /* @__PURE__ */ jsx("div", {
|
|
1917
|
-
ref: elementRef,
|
|
1918
|
-
className
|
|
1919
|
-
}),
|
|
1920
|
-
isAcknowledged,
|
|
1921
|
-
isCancelled,
|
|
1922
|
-
isEnabled: criiptoConfiguration === null || criiptoConfiguration === void 0 ? void 0 : criiptoConfiguration.client.qr_enabled,
|
|
1923
|
-
error,
|
|
1924
|
-
retry: handleRetry,
|
|
1925
|
-
redirect
|
|
1926
|
-
});
|
|
1927
|
-
};
|
|
1928
|
-
//#endregion
|
|
1929
1849
|
//#region src/use-criipto-verify.ts
|
|
1930
1850
|
function useCriiptoVerify() {
|
|
1931
1851
|
const { result, claims, loginWithRedirect, loginWithPopup, acrValues, isLoading, isInitializing, logout, checkSession } = useContext(CriiptoVerifyContext);
|
|
@@ -1943,6 +1863,6 @@ function useCriiptoVerify() {
|
|
|
1943
1863
|
};
|
|
1944
1864
|
}
|
|
1945
1865
|
//#endregion
|
|
1946
|
-
export { AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, OAuth2Error,
|
|
1866
|
+
export { AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, OAuth2Error, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
|
|
1947
1867
|
|
|
1948
1868
|
//# sourceMappingURL=index.js.map
|