@criipto/verify-react 5.0.2 → 6.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 CHANGED
@@ -1,22 +1,27 @@
1
1
  # @criipto/verify-react
2
2
 
3
- Accept MitID, Swedish BankID, Norwegian BankID and more logins in your React app with `@criipto/verify-react`.
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
- ## App switch support
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
- ## Getting Started
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
- Setup the Criipto Verify SDK by wrapping your application in `CriiptoVerifyProvider`:
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="{YOUR_CRIIPTO_DOMAIN}"
32
- clientID="{YOUR_CRIIPTO_APPLICATION_CLIENT_ID}"
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
- You can find your domain and application client id on the [Criipto Dashboard](https://dashboard.criipto.com/).
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.
47
+
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
42
73
 
43
- Use the `useCriiptoVerify` hook + the `AuthMethodSelector` component in your React app to render a login screen.
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,56 @@ 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
+ ## Send the user directly to an eID login screen
115
+
116
+ If you don't need the method selector, use `loginWithRedirect` (or `loginWithPopup`) and pass a single eID method identifier in `acrValues`.
117
+
118
+ ```jsx
119
+ // src/App.js
120
+ import React from 'react';
121
+ import { useCriiptoVerify } from '@criipto/verify-react';
122
+
123
+ export default function App() {
124
+ const { result, loginWithRedirect } = useCriiptoVerify();
125
+
126
+ if (result?.id_token) {
127
+ return <pre>{JSON.stringify(result.id_token, null, 2)}</pre>;
128
+ }
129
+
130
+ return (
131
+ <button onClick={() => loginWithRedirect({ acrValues: 'urn:grn:authn:dk:mitid:substantial' })}>
132
+ Log in with MitID
133
+ </button>
134
+ );
135
+ }
136
+ ```
68
137
 
69
138
  ## CORS
70
139
 
71
- The library makes fetch requests to Criipto for two reasons:
140
+ The SDK makes fetch requests to Idura for two reasons:
72
141
 
73
142
  1. To load application configuration when the provider mounts.
74
143
  2. To push the authorization request (PAR) when a user clicks a login button.
75
144
 
76
- Make sure that the origin your React app runs on is included in the list of callback URLs for your application. Otherwise, both calls will fail with CORS errors.
145
+ 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
146
 
78
147
  ## Sessions
79
148
 
80
- If you want to use `@criipto/verify-react` for session management (rather than one-off authentication) you can configure a `sessionStore`:
149
+ If you want to use the SDK for session management (rather than one-off authentication), you can configure a `sessionStore`:
81
150
 
82
151
  ```jsx
83
152
  // src/index.js
@@ -89,8 +158,8 @@ import App from './App';
89
158
 
90
159
  ReactDOM.render(
91
160
  <CriiptoVerifyProvider
92
- domain="{YOUR_CRIIPTO_DOMAIN}"
93
- clientID="{YOUR_CRIIPTO_APPLICATION_CLIENT_ID}"
161
+ domain="{YOUR_IDURA_DOMAIN}"
162
+ clientID="{YOUR_IDURA_APPLICATION_CLIENT_ID}"
94
163
  redirectUri={window.location.href}
95
164
  sessionStore={window.sessionStorage} // or window.localStorage
96
165
  >
@@ -100,11 +169,11 @@ ReactDOM.render(
100
169
  );
101
170
  ```
102
171
 
103
- When a `sessionStore` is configured the library will store the id_token in your chosen storage (sessionStorage or localStorage) and invalidate the token once it expires.
172
+ 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
173
 
105
- The library will also attempt to retrieve a user token on page load via SSO (if your criipto domain has SSO enabled).
174
+ 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
175
 
107
- You may wish to increase the "Token lifetime" setting of your Criipto Application.
176
+ For longer sessions, you can increase the **Token lifetime** setting of your Idura application (**Applications → your app → Advanced Options**).
108
177
 
109
178
  ```jsx
110
179
  // src/App.js
@@ -126,7 +195,7 @@ export default function App() {
126
195
  <React.Fragment>
127
196
  {error ? (
128
197
  <p>
129
- An error occured:{' '}
198
+ An error occurred:{' '}
130
199
  {error instanceof OAuth2Error
131
200
  ? `${error.error} (${error.error_description})`
132
201
  : String(error)}
@@ -139,18 +208,34 @@ export default function App() {
139
208
  }
140
209
  ```
141
210
 
142
- ### Logging Out
211
+ ### Logging out
143
212
 
144
- `@criipto/verify-react` offers the logout method you can use to clear session storage and log out of any existing SSO session.
213
+ The `logout` method clears the session store and ends any existing SSO session.
145
214
 
146
215
  ```jsx
147
- const {logout} = useCriiptoVerify();
148
- ...
149
- <button onClick={() => logout({redirectUri: window.location.href})}>
150
- Log Out
151
- </button>
216
+ // src/App.js
217
+ import React from 'react';
218
+ import { useCriiptoVerify, AuthMethodSelector } from '@criipto/verify-react';
219
+ import '@criipto/verify-react/index.css';
220
+
221
+ export default function App() {
222
+ const { claims, logout } = useCriiptoVerify();
223
+
224
+ if (claims) {
225
+ return (
226
+ <React.Fragment>
227
+ <pre>{JSON.stringify(claims, null, 2)}</pre>
228
+ <button onClick={() => logout({ redirectUri: window.location.href })}>Log out</button>
229
+ </React.Fragment>
230
+ );
231
+ }
232
+
233
+ return <AuthMethodSelector />;
234
+ }
152
235
  ```
153
236
 
237
+ `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)).
238
+
154
239
  ## useEffect + loginWithRedirect
155
240
 
156
241
  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 +249,10 @@ useEffect(() => {
164
249
  }, [isLoading, isInitializing]);
165
250
  ```
166
251
 
167
- ## Criipto
252
+ ## Idura
253
+
254
+ Learn more about Idura and sign up for a free developer account at [idura.eu](https://idura.eu).
255
+
256
+ ### Why the package is named `@criipto/verify-react`
168
257
 
169
- Learn more about Criipto and sign up for your free developer account at [criipto.com](https://www.criipto.com).
258
+ 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
@@ -4,7 +4,7 @@ import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1, PKCEPublicPart,
4
4
  import * as react_jsx_runtime0 from "react/jsx-runtime";
5
5
 
6
6
  //#region src/context.d.ts
7
- type ResultSource = 'QRCode' | 'SEBankIDQrCode' | 'SEBankIDSameDeviceButton' | 'redirect' | 'popup';
7
+ type ResultSource = 'SEBankIDQrCode' | 'SEBankIDSameDeviceButton' | 'redirect' | 'popup';
8
8
  type Result = {
9
9
  id_token: string;
10
10
  state?: string;
@@ -159,34 +159,6 @@ declare function AuthButtonGroup(props: {
159
159
  children: React.ReactNode;
160
160
  }): react_jsx_runtime0.JSX.Element;
161
161
  //#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
162
  //#region src/components/SEBankIDQRCode.d.ts
191
163
  interface Props {
192
164
  redirectUri?: string;
@@ -263,5 +235,5 @@ declare function useCriiptoVerify(): {
263
235
  //#region src/utils.d.ts
264
236
  declare function filterAcrValues(input: string[]): string[];
265
237
  //#endregion
266
- export { type Action, AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, type Language, OAuth2Error, QRCode, type Result, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
238
+ export { type Action, AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, type Language, OAuth2Error, type Result, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
267
239
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import React, { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
2
- import CriiptoAuth, { OAuth2Error, OAuth2Error as OAuth2Error$1, UserCancelledError, clearPKCEState, generatePKCE, parseAuthorizeResponseFromLocation, savePKCEState } from "@criipto/auth-js";
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$1 from "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 = "5.0.2";
48
+ var version = "6.0.0";
49
49
  //#endregion
50
50
  //#region src/i18n/en.ts
51
51
  const en = {
@@ -1215,7 +1215,7 @@ function useDraw(qrCode, options) {
1215
1215
  if (!qrCode) return;
1216
1216
  let isSubscribed = true;
1217
1217
  _asyncToGenerator(function* () {
1218
- const qrImage = yield QRCode$1.toDataURL(qrCode, {
1218
+ const qrImage = yield QRCode.toDataURL(qrCode, {
1219
1219
  errorCorrectionLevel: "low",
1220
1220
  scale: 10,
1221
1221
  width,
@@ -1819,113 +1819,6 @@ function Sweden(props) {
1819
1819
  });
1820
1820
  }
1821
1821
  //#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
1822
  //#region src/use-criipto-verify.ts
1930
1823
  function useCriiptoVerify() {
1931
1824
  const { result, claims, loginWithRedirect, loginWithPopup, acrValues, isLoading, isInitializing, logout, checkSession } = useContext(CriiptoVerifyContext);
@@ -1943,6 +1836,6 @@ function useCriiptoVerify() {
1943
1836
  };
1944
1837
  }
1945
1838
  //#endregion
1946
- export { AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, OAuth2Error, QRCode, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
1839
+ export { AuthMethodButtonContainer as AuthButton, AuthMethodButtonContainer as AuthMethodButton, AuthMethodButtonComponent as AuthButtonComponent, AuthButtonGroup, AuthMethodSelector, Sweden as AuthMethodSelectorSweden, CriiptoVerifyProvider, OAuth2Error, SEBankIDQrCode as SEBankIDQRCode, actions, filterAcrValues, useCriiptoVerify };
1947
1840
 
1948
1841
  //# sourceMappingURL=index.js.map