@descope/react-sdk 0.0.52-alpha.0 → 0.0.52-alpha.10
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 +128 -12
- package/dist/index.d.ts +27 -17
- package/dist/index.js +1 -1
- package/package.json +91 -78
package/README.md
CHANGED
|
@@ -1,29 +1,56 @@
|
|
|
1
1
|
# @descope/react-sdk
|
|
2
|
+
|
|
2
3
|
This library lets you consume your login pages created by Descope console-app in your application
|
|
3
4
|
Under the hood, it uses [web-js-sdk](https://github.com/descope/web-js-sdk)
|
|
4
5
|
|
|
5
6
|
## Usage
|
|
7
|
+
|
|
6
8
|
### Install the package
|
|
9
|
+
|
|
7
10
|
```bash
|
|
8
11
|
npm install @descope/react-sdk
|
|
9
12
|
```
|
|
10
13
|
|
|
11
14
|
### Render it in your application
|
|
15
|
+
|
|
12
16
|
#### Wrap your app with Auth Provider
|
|
17
|
+
|
|
13
18
|
```js
|
|
14
|
-
import { AuthProvider } from '@descope/react-sdk'
|
|
19
|
+
import { AuthProvider } from '@descope/react-sdk';
|
|
15
20
|
|
|
16
21
|
const AppRoot = () => {
|
|
22
|
+
return (
|
|
23
|
+
<AuthProvider projectId="myProjectId">
|
|
24
|
+
<App />
|
|
25
|
+
</AuthProvider>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
#### Use Descope to render specific flow
|
|
31
|
+
|
|
32
|
+
You can use **default flows** or **provide flow id** directly to the Descope component
|
|
33
|
+
|
|
34
|
+
##### 1. Default flows
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { SignInFlow } from '@descope/react-sdk'
|
|
38
|
+
// you can choose flow to run from the following
|
|
39
|
+
// import { SignUpFlow } from '@descope/react-sdk'
|
|
40
|
+
// import { SignUpOrInFlow } from '@descope/react-sdk'
|
|
41
|
+
|
|
42
|
+
const App = () => {
|
|
17
43
|
return (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
{...}
|
|
45
|
+
<SignInFlow
|
|
46
|
+
onSuccess={(e) => console.log('Logged in!')}
|
|
47
|
+
onError={(e) => console.log('Could not logged in!')}
|
|
48
|
+
/>
|
|
23
49
|
)
|
|
24
50
|
}
|
|
25
51
|
```
|
|
26
|
-
|
|
52
|
+
|
|
53
|
+
##### 2. Provide flow id
|
|
27
54
|
|
|
28
55
|
```js
|
|
29
56
|
import { Descope } from '@descope/react-sdk'
|
|
@@ -31,14 +58,103 @@ import { Descope } from '@descope/react-sdk'
|
|
|
31
58
|
const App = () => {
|
|
32
59
|
return (
|
|
33
60
|
{...}
|
|
34
|
-
<Descope
|
|
35
|
-
flowId="myFlowId"
|
|
61
|
+
<Descope
|
|
62
|
+
flowId="myFlowId"
|
|
36
63
|
onSuccess={(e) => console.log('Logged in!')}
|
|
37
64
|
onError={(e) => console.log('Could not logged in!')}
|
|
38
|
-
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Use the `useAuth` hook in your components in order to access authentication state and utilities
|
|
71
|
+
|
|
72
|
+
This can be helpful to implement application-specific logic. Examples:
|
|
73
|
+
|
|
74
|
+
- Render different components if current session is authenticated
|
|
75
|
+
- Render user's content
|
|
76
|
+
- Logout button
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
import { useAuth } from '@descope/react-sdk'
|
|
80
|
+
|
|
81
|
+
const App = () => {
|
|
82
|
+
// NOTE - `useAuth` should be used inside `AuthProvider` context,
|
|
83
|
+
// and will throw an exception if this requirement is not met
|
|
84
|
+
const { authenticated, user, logout } = useAuth()
|
|
85
|
+
return (
|
|
86
|
+
{...}
|
|
87
|
+
{
|
|
88
|
+
// render different components if current session is authenticated
|
|
89
|
+
authenticated && <MyPrivateComponent />
|
|
90
|
+
}
|
|
91
|
+
{
|
|
92
|
+
// render user's content
|
|
93
|
+
authenticated && <div>Hello ${user.name}</div>
|
|
94
|
+
}
|
|
95
|
+
{
|
|
96
|
+
// logout button
|
|
97
|
+
authenticated && <button onClick={logout}>Logout</div>
|
|
98
|
+
}
|
|
39
99
|
)
|
|
40
100
|
}
|
|
41
101
|
```
|
|
42
102
|
|
|
43
|
-
|
|
44
|
-
|
|
103
|
+
#### Session token server validation (pass session token to server API)
|
|
104
|
+
|
|
105
|
+
When developing a full-stack application, it is common to have private server API which requires a valid session token:
|
|
106
|
+
|
|
107
|
+

|
|
108
|
+
|
|
109
|
+
Note: Descope also provides server-side SDKs in various languages (NodeJS, Go, Python, etc). Descope's server SDKs have out-of-the-box session validation API that supports the options described bellow. To read more about session validation, Read [this section](https://docs.descope.com/guides/gettingstarted/#session-validation) in Descope documentation.
|
|
110
|
+
|
|
111
|
+
The mechanism to pass session token depends on the Descope project's "Token response method" configuration.
|
|
112
|
+
|
|
113
|
+
##### 1. Manage in cookies
|
|
114
|
+
|
|
115
|
+
- Descope sets session token as cookie, which automatically sent each server api request. This option is more secure and is the recommended method for managing tokens, but for this option to work well with the browser - you must also configure a CNAME record for the custom domain listed, which will give a unified log in experience and securely restrict access to the session tokens that are stored in the cookies.
|
|
116
|
+
|
|
117
|
+
When this option is configured, the browser will automatically add the session token cookie to the server in every request.
|
|
118
|
+
|
|
119
|
+
##### 2. Manage in response body
|
|
120
|
+
|
|
121
|
+
- Descope API returns session token in body. In this option, The React application should pass session cookie (`const { sessionToken } = useAuth()`) as Authorization header. This option never requires a custom domain, and is recommended for testing or while working in a sandbox environment.
|
|
122
|
+
|
|
123
|
+
An example for using session token,
|
|
124
|
+
|
|
125
|
+
```js
|
|
126
|
+
import { useAuth } from '@descope/react-sdk'
|
|
127
|
+
import { useCallback } from 'react'
|
|
128
|
+
|
|
129
|
+
const App = () => {
|
|
130
|
+
const { sessionToken } = useAuth()
|
|
131
|
+
|
|
132
|
+
const onClick = useCallback(() => {
|
|
133
|
+
fetch('https://localhost:3002/api/some-path' {
|
|
134
|
+
method: 'GET',
|
|
135
|
+
headers: { Authorization: `Bearer ${sessionToken}` }
|
|
136
|
+
})
|
|
137
|
+
},[sessionToken])
|
|
138
|
+
return (
|
|
139
|
+
{...}
|
|
140
|
+
{
|
|
141
|
+
// button that triggers an API that may use session token
|
|
142
|
+
<button onClick={onClick}>Click Me</div>
|
|
143
|
+
}
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Contributing to this project
|
|
149
|
+
|
|
150
|
+
In order to use this repo locally
|
|
151
|
+
|
|
152
|
+
- Clone this repository
|
|
153
|
+
- Navigate to repository directory
|
|
154
|
+
- Run `npm i`
|
|
155
|
+
- Edit `src/app/index.tsx` in the following way
|
|
156
|
+
- Set `projectId` prop - replace `<project-id>` with your project id
|
|
157
|
+
- Set `flowId` prop - Replace `<flow-id>` (for example - `sign-up-or-in`)
|
|
158
|
+
- Optional - set a different `baseUrl` (for example - `http://localhost:8000`)
|
|
159
|
+
- Run `npm run start`
|
|
160
|
+
- Go to `http://localhost:3000/` and start flow
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import React, { FC, DOMAttributes } from 'react';
|
|
2
3
|
import DescopeWc from '@descope/web-component';
|
|
4
|
+
import createSdk from '@descope/web-js-sdk';
|
|
5
|
+
|
|
6
|
+
interface IAuthProviderProps {
|
|
7
|
+
projectId: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
children?: JSX.Element;
|
|
10
|
+
}
|
|
11
|
+
declare const AuthProvider: FC<IAuthProviderProps>;
|
|
3
12
|
|
|
4
13
|
declare global {
|
|
5
14
|
namespace JSX {
|
|
@@ -8,6 +17,7 @@ declare global {
|
|
|
8
17
|
}
|
|
9
18
|
}
|
|
10
19
|
}
|
|
20
|
+
declare type Sdk = ReturnType<typeof createSdk>;
|
|
11
21
|
declare type CustomEvents<K extends string> = {
|
|
12
22
|
[key in K]: (event: CustomEvent) => void;
|
|
13
23
|
};
|
|
@@ -39,26 +49,26 @@ interface User {
|
|
|
39
49
|
verifiedPhone?: boolean;
|
|
40
50
|
tenants?: string[];
|
|
41
51
|
}
|
|
42
|
-
|
|
43
|
-
declare const useAuth: () => {
|
|
44
|
-
projectId: string;
|
|
45
|
-
baseUrl: string;
|
|
52
|
+
interface IAuth {
|
|
46
53
|
authenticated: boolean;
|
|
47
|
-
user
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
user?: User;
|
|
55
|
+
sessionToken?: string;
|
|
56
|
+
logout: Sdk['logout'];
|
|
57
|
+
me: Sdk['me'];
|
|
58
|
+
}
|
|
59
|
+
interface DescopeProps {
|
|
51
60
|
flowId: string;
|
|
52
61
|
onSuccess?: DescopeCustomElement['onsuccess'];
|
|
53
62
|
onError?: DescopeCustomElement['onerror'];
|
|
54
63
|
}
|
|
55
|
-
declare
|
|
64
|
+
declare type DefaultFlowProps = Omit<DescopeProps, 'flowId'>;
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
declare const SignInFlow: (props: DefaultFlowProps) => JSX.Element;
|
|
67
|
+
declare const SignUpFlow: (props: DefaultFlowProps) => JSX.Element;
|
|
68
|
+
declare const SignUpOrInFlow: (props: DefaultFlowProps) => JSX.Element;
|
|
69
|
+
|
|
70
|
+
declare const Descope: React.ForwardRefExoticComponent<DescopeProps & React.RefAttributes<HTMLElement>>;
|
|
71
|
+
|
|
72
|
+
declare const useAuth: () => IAuth;
|
|
63
73
|
|
|
64
|
-
export { AuthProvider, Descope, useAuth };
|
|
74
|
+
export { AuthProvider, Descope, SignInFlow, SignUpFlow, SignUpOrInFlow, useAuth };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e,{
|
|
1
|
+
import e from"@descope/web-js-sdk";import o,{useState as r,useMemo as t,useEffect as s,useRef as n,useImperativeHandle as c,useCallback as i}from"react";import"@descope/web-component";const u=o.createContext(void 0),d=({projectId:n,baseUrl:c,children:i})=>{const[d,a]=r({}),[l,p]=r(""),f=t((()=>{if(n)return e({projectId:n,baseUrl:c,hooks:{beforeRequest:e=>{const o=e;return o.headers={...o.headers,"x-descope-sdk-name":"react","x-descope-sdk-version":"0.0.52-alpha.10"},o}}})}),[n,c]);s((()=>{if(!f)return;const e=f.onSessionTokenChange(p),o=f.onUserChange(a);return()=>{e?.(),o?.()}}),[f]);const m=t((()=>({sdk:f,projectId:n,baseUrl:c,user:d,sessionToken:l,setUser:a,setSessionToken:p})),[l,d,n,c]);return o.createElement(u.Provider,{value:m},i)};d.defaultProps={baseUrl:"",children:void 0};const a=o.forwardRef((({flowId:e,onSuccess:r,onError:t},d)=>{const a=n();c(d,(()=>a.current));const{projectId:l,baseUrl:p,setUser:f,setSessionToken:m}=o.useContext(u),h=i((e=>{f(e.detail?.user);const o=e.detail?.sessionJwt;m(o),r&&r(e)}),[f,m,r]);return s((()=>{const e=a.current;return e?.addEventListener("success",h),t&&e?.addEventListener("error",t),()=>{t&&e?.removeEventListener("error",t),e?.removeEventListener("success",h)}}),[a,t,h]),o.createElement("descope-wc",{"project-id":l,"flow-id":e,"base-url":p,ref:a})}));a.defaultProps={onError:void 0,onSuccess:void 0};const l=e=>o.createElement(a,{...e,flowId:"sign-in"}),p=e=>o.createElement(a,{...e,flowId:"sign-up"}),f=e=>o.createElement(a,{...e,flowId:"sign-up-or-in"}),m=()=>{const e=o.useContext(u);if(!e)throw Error("You can only use 'useAuth' in the context of <AuthProvider />");const{user:r,sessionToken:s,sdk:n}=e,c=i(((...e)=>{if(!n)throw Error("You can only use 'logout' after sdk initialization. Make sure to supply 'projectId' to <AuthProvider /> component");return n.logout(...e)}),[n]),d=i(((...e)=>{if(!n)throw Error("You can only use 'me' after sdk initialization. Make sure to supply 'projectId' to <AuthProvider /> component");return n.me(...e)}),[n]);return t((()=>({authenticated:!!s,user:r,sessionToken:s,logout:c,me:d})),[r,s,n])};export{d as AuthProvider,a as Descope,l as SignInFlow,p as SignUpFlow,f as SignUpOrInFlow,m as useAuth};
|
package/package.json
CHANGED
|
@@ -1,80 +1,93 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
2
|
+
"name": "@descope/react-sdk",
|
|
3
|
+
"version": "0.0.52-alpha.10",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"description": "Descope React SDK",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/descope/react-sdk.git"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@descope/web-component": "0.1.0-alpha.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@babel/core": "7.19.6",
|
|
20
|
+
"@babel/preset-env": "7.19.4",
|
|
21
|
+
"@babel/preset-react": "7.18.6",
|
|
22
|
+
"@babel/preset-typescript": "7.18.6",
|
|
23
|
+
"@open-wc/rollup-plugin-html": "^1.2.5",
|
|
24
|
+
"@rollup/plugin-commonjs": "^21.0.1",
|
|
25
|
+
"@rollup/plugin-node-resolve": "^13.1.1",
|
|
26
|
+
"@rollup/plugin-replace": "^3.0.0",
|
|
27
|
+
"@rollup/plugin-typescript": "^8.3.0",
|
|
28
|
+
"@testing-library/jest-dom": "5.16.5",
|
|
29
|
+
"@testing-library/react": "13.4.0",
|
|
30
|
+
"@testing-library/user-event": "14.4.3",
|
|
31
|
+
"@types/jest": "^27.0.2",
|
|
32
|
+
"@types/react": "18.0.17",
|
|
33
|
+
"@types/react-dom": "18.0.7",
|
|
34
|
+
"babel-jest": "27.5.1",
|
|
35
|
+
"eslint": "8.20.0",
|
|
36
|
+
"eslint-config-airbnb": "19.0.4",
|
|
37
|
+
"eslint-config-airbnb-typescript": "17.0.0",
|
|
38
|
+
"eslint-config-prettier": "8.5.0",
|
|
39
|
+
"eslint-config-standard": "17.0.0",
|
|
40
|
+
"eslint-import-resolver-typescript": "2.7.1",
|
|
41
|
+
"eslint-plugin-import": "2.26.0",
|
|
42
|
+
"eslint-plugin-jest": "26.9.0",
|
|
43
|
+
"eslint-plugin-jest-dom": "4.0.2",
|
|
44
|
+
"eslint-plugin-jest-formatting": "3.1.0",
|
|
45
|
+
"eslint-plugin-jsx-a11y": "6.6.1",
|
|
46
|
+
"eslint-plugin-n": "15.3.0",
|
|
47
|
+
"eslint-plugin-no-only-tests": "2.6.0",
|
|
48
|
+
"eslint-plugin-prefer-arrow": "1.2.3",
|
|
49
|
+
"eslint-plugin-prettier": "4.2.1",
|
|
50
|
+
"eslint-plugin-promise": "6.1.1",
|
|
51
|
+
"eslint-plugin-react": "7.31.10",
|
|
52
|
+
"eslint-plugin-react-hooks": "4.6.0",
|
|
53
|
+
"eslint-plugin-testing-library": "5.6.0",
|
|
54
|
+
"husky": "^8.0.1",
|
|
55
|
+
"jest": "^27.3.1",
|
|
56
|
+
"lint-staged": "^13.0.3",
|
|
57
|
+
"pretty-quick": "^3.1.3",
|
|
58
|
+
"react": "18.2.0",
|
|
59
|
+
"react-dom": "18.2.0",
|
|
60
|
+
"rollup": "^2.62.0",
|
|
61
|
+
"rollup-plugin-auto-external": "^2.0.0",
|
|
62
|
+
"rollup-plugin-browsersync": "^1.3.3",
|
|
63
|
+
"rollup-plugin-define": "^1.0.1",
|
|
64
|
+
"rollup-plugin-delete": "^2.0.0",
|
|
65
|
+
"rollup-plugin-dts": "^4.2.2",
|
|
66
|
+
"rollup-plugin-livereload": "^2.0.5",
|
|
67
|
+
"rollup-plugin-serve": "^1.1.0",
|
|
68
|
+
"rollup-plugin-terser": "^7.0.2",
|
|
69
|
+
"ts-jest": "^27.0.7",
|
|
70
|
+
"ts-node": "10.9.1",
|
|
71
|
+
"typescript": "^4.5.3"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@types/react": ">=16",
|
|
75
|
+
"react": ">=16"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"start": "npm run build && rollup -c rollup.config.app.js -w",
|
|
79
|
+
"build": "rollup -c",
|
|
80
|
+
"prepare": "husky install",
|
|
81
|
+
"test": "jest",
|
|
82
|
+
"lint": "eslint '+(src|test|testUtils)/**/*.ts' --fix",
|
|
83
|
+
"format": "prettier . -w --ignore-path .gitignore",
|
|
84
|
+
"format-check": "prettier . --check --ignore-path .gitignore",
|
|
85
|
+
"format-lint": "pretty-quick --staged --ignore-path .gitignore && lint-staged",
|
|
86
|
+
"prepublishOnly": "npm run build"
|
|
87
|
+
},
|
|
88
|
+
"lint-staged": {
|
|
89
|
+
"+(src|test|examples)/**/*.{js,ts,jsx,tsx}": [
|
|
90
|
+
"npm run lint"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
80
93
|
}
|