@crownpeak/dqm-react-component 1.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/AUTHENTICATION.md +281 -0
- package/BACKEND-API.md +1829 -0
- package/CHANGELOG.md +28 -0
- package/DEVELOPMENT.md +339 -0
- package/EXAMPLES.md +194 -0
- package/LICENSE +22 -0
- package/QUICKSTART.md +200 -0
- package/README.md +213 -0
- package/dist/DQMSidebar.d.ts +5 -0
- package/dist/DQMSidebar.d.ts.map +1 -0
- package/dist/ErrorBoundary.d.ts +34 -0
- package/dist/ErrorBoundary.d.ts.map +1 -0
- package/dist/auth-ui/assets/index-CehNKFGj.js +158 -0
- package/dist/auth-ui/index.html +30 -0
- package/dist/components/auth/DQMLogin.d.ts +16 -0
- package/dist/components/auth/DQMLogin.d.ts.map +1 -0
- package/dist/components/auth/OAuth2CallbackHandler.d.ts +15 -0
- package/dist/components/auth/OAuth2CallbackHandler.d.ts.map +1 -0
- package/dist/components/auth/index.d.ts +3 -0
- package/dist/components/auth/index.d.ts.map +1 -0
- package/dist/components/cards/CategoryCard.d.ts +2 -0
- package/dist/components/cards/CategoryCard.d.ts.map +1 -0
- package/dist/components/cards/FailedCheckpointsCard.d.ts +2 -0
- package/dist/components/cards/FailedCheckpointsCard.d.ts.map +1 -0
- package/dist/components/cards/QualityOverviewCard.d.ts +2 -0
- package/dist/components/cards/QualityOverviewCard.d.ts.map +1 -0
- package/dist/components/cards/index.d.ts +4 -0
- package/dist/components/cards/index.d.ts.map +1 -0
- package/dist/components/common/CircularProgressWithLabel.d.ts +5 -0
- package/dist/components/common/CircularProgressWithLabel.d.ts.map +1 -0
- package/dist/components/common/index.d.ts +2 -0
- package/dist/components/common/index.d.ts.map +1 -0
- package/dist/components/renderers/BrowserViewRenderer.d.ts +9 -0
- package/dist/components/renderers/BrowserViewRenderer.d.ts.map +1 -0
- package/dist/components/renderers/SafeParsedHtml.d.ts +4 -0
- package/dist/components/renderers/SafeParsedHtml.d.ts.map +1 -0
- package/dist/components/renderers/ShadowDOMRenderer.d.ts +11 -0
- package/dist/components/renderers/ShadowDOMRenderer.d.ts.map +1 -0
- package/dist/components/renderers/index.d.ts +4 -0
- package/dist/components/renderers/index.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarContent.d.ts +2 -0
- package/dist/components/sidebar/SidebarContent.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarFooter.d.ts +5 -0
- package/dist/components/sidebar/SidebarFooter.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarHeader.d.ts +2 -0
- package/dist/components/sidebar/SidebarHeader.d.ts.map +1 -0
- package/dist/components/sidebar/SidebarSkeleton.d.ts +5 -0
- package/dist/components/sidebar/SidebarSkeleton.d.ts.map +1 -0
- package/dist/components/sidebar/StyledDrawer.d.ts +2 -0
- package/dist/components/sidebar/StyledDrawer.d.ts.map +1 -0
- package/dist/components/sidebar/StyledFab.d.ts +4 -0
- package/dist/components/sidebar/StyledFab.d.ts.map +1 -0
- package/dist/components/sidebar/index.d.ts +7 -0
- package/dist/components/sidebar/index.d.ts.map +1 -0
- package/dist/index.cjs +113 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13712 -0
- package/dist/index.js.map +1 -0
- package/dist/server/config.js +21 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/index.js +74 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/authenticate.js +31 -0
- package/dist/server/middleware/authenticate.js.map +1 -0
- package/dist/server/middleware/errorHandler.js +8 -0
- package/dist/server/middleware/errorHandler.js.map +1 -0
- package/dist/server/routes/auth.js +142 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/dqm.js +138 -0
- package/dist/server/routes/dqm.js.map +1 -0
- package/dist/server/services/dqmClient.js +127 -0
- package/dist/server/services/dqmClient.js.map +1 -0
- package/dist/server/services/sessionStore.js +250 -0
- package/dist/server/services/sessionStore.js.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/colors/GenerateCategoryColors.d.ts +12 -0
- package/dist/utils/colors/GenerateCategoryColors.d.ts.map +1 -0
- package/dist/utils/localStorage.d.ts +4 -0
- package/dist/utils/localStorage.d.ts.map +1 -0
- package/dist/utils/storage.d.ts +28 -0
- package/dist/utils/storage.d.ts.map +1 -0
- package/package.json +124 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# DQM Authentication Configuration Examples
|
|
2
|
+
|
|
3
|
+
This document shows different ways to configure authentication for the DQM Sidebar component.
|
|
4
|
+
|
|
5
|
+
## 1. Direct Credentials (Simplest)
|
|
6
|
+
|
|
7
|
+
Pass API credentials directly as props:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
11
|
+
|
|
12
|
+
function App() {
|
|
13
|
+
const [open, setOpen] = useState(false);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<DQMSidebar
|
|
17
|
+
open={open}
|
|
18
|
+
onClose={() => setOpen(false)}
|
|
19
|
+
onOpen={() => setOpen(true)}
|
|
20
|
+
config={{
|
|
21
|
+
apiKey: process.env.REACT_APP_DQM_API_KEY,
|
|
22
|
+
websiteId: process.env.REACT_APP_DQM_WEBSITE_ID,
|
|
23
|
+
}}
|
|
24
|
+
/>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 2. LocalStorage (Default Behavior)
|
|
30
|
+
|
|
31
|
+
If no credentials are provided via props, the component will check `localStorage` and show a login form if credentials are missing:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
35
|
+
|
|
36
|
+
function App() {
|
|
37
|
+
const [open, setOpen] = useState(false);
|
|
38
|
+
|
|
39
|
+
// On first open, user will see login form
|
|
40
|
+
// Credentials are stored in localStorage after successful login
|
|
41
|
+
return (
|
|
42
|
+
<DQMSidebar
|
|
43
|
+
open={open}
|
|
44
|
+
onClose={() => setOpen(false)}
|
|
45
|
+
onOpen={() => setOpen(true)}
|
|
46
|
+
config={{
|
|
47
|
+
useLocalStorage: true, // Default: true
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## 3. Backend Authentication (Custom Token Exchange)
|
|
55
|
+
|
|
56
|
+
Use your own Express.js backend to manage credentials:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
60
|
+
|
|
61
|
+
function App() {
|
|
62
|
+
const [open, setOpen] = useState(false);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<DQMSidebar
|
|
66
|
+
open={open}
|
|
67
|
+
onClose={() => setOpen(false)}
|
|
68
|
+
onOpen={() => setOpen(true)}
|
|
69
|
+
config={{
|
|
70
|
+
authBackendUrl: 'https://api.yourcompany.com',
|
|
71
|
+
useLocalStorage: true, // Optional: cache credentials
|
|
72
|
+
}}
|
|
73
|
+
onAuthSuccess={(credentials) => {
|
|
74
|
+
console.log('Authenticated:', credentials);
|
|
75
|
+
}}
|
|
76
|
+
onAuthError={(error) => {
|
|
77
|
+
console.error('Auth failed:', error);
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Backend API Requirements
|
|
85
|
+
|
|
86
|
+
Your backend must implement this endpoint:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// POST /auth/token
|
|
90
|
+
// Response:
|
|
91
|
+
{
|
|
92
|
+
"apiKey": "your-dqm-api-key",
|
|
93
|
+
"websiteId": "your-website-id"
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 4. OAuth2 Flow
|
|
98
|
+
|
|
99
|
+
For enterprise SSO integration:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
103
|
+
|
|
104
|
+
function App() {
|
|
105
|
+
const [open, setOpen] = useState(false);
|
|
106
|
+
|
|
107
|
+
// TODO: verify that your backend supports OAuth2 token exchange
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<DQMSidebar
|
|
111
|
+
open={open}
|
|
112
|
+
onClose={() => setOpen(false)}
|
|
113
|
+
onOpen={() => setOpen(true)}
|
|
114
|
+
config={{
|
|
115
|
+
authBackendUrl: 'https://api.yourcompany.com',
|
|
116
|
+
oauth2Config: {
|
|
117
|
+
authUrl: 'https://oauth.yourcompany.com/authorize',
|
|
118
|
+
tokenUrl: 'https://oauth.yourcompany.com/token',
|
|
119
|
+
clientId: 'your-oauth-client-id',
|
|
120
|
+
redirectUri: window.location.origin + '/dqm/callback',
|
|
121
|
+
scope: 'dqm:read',
|
|
122
|
+
},
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### OAuth2 Backend Requirements
|
|
130
|
+
|
|
131
|
+
Your backend must implement:
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// POST /auth/oauth2/callback
|
|
135
|
+
// Body: { code: string, redirectUri: string }
|
|
136
|
+
// Response:
|
|
137
|
+
{
|
|
138
|
+
"apiKey": "your-dqm-api-key",
|
|
139
|
+
"websiteId": "your-website-id"
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 5. Hybrid Configuration
|
|
144
|
+
|
|
145
|
+
Combine multiple authentication methods with priority:
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import { DQMSidebar } from '@crownpeak/dqm-react-component';
|
|
149
|
+
|
|
150
|
+
function App() {
|
|
151
|
+
const [open, setOpen] = useState(false);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<DQMSidebar
|
|
155
|
+
open={open}
|
|
156
|
+
onClose={() => setOpen(false)}
|
|
157
|
+
onOpen={() => setOpen(true)}
|
|
158
|
+
config={{
|
|
159
|
+
// Priority 1: Direct credentials (if provided)
|
|
160
|
+
apiKey: process.env.REACT_APP_DQM_API_KEY,
|
|
161
|
+
websiteId: process.env.REACT_APP_DQM_WEBSITE_ID,
|
|
162
|
+
|
|
163
|
+
// Priority 2: LocalStorage (if no props provided)
|
|
164
|
+
useLocalStorage: true,
|
|
165
|
+
|
|
166
|
+
// Priority 3: Backend authentication (fallback)
|
|
167
|
+
authBackendUrl: 'https://api.yourcompany.com',
|
|
168
|
+
oauth2Config: {
|
|
169
|
+
authUrl: 'https://oauth.yourcompany.com/authorize',
|
|
170
|
+
tokenUrl: 'https://oauth.yourcompany.com/token',
|
|
171
|
+
clientId: 'your-oauth-client-id',
|
|
172
|
+
redirectUri: window.location.origin + '/dqm/callback',
|
|
173
|
+
},
|
|
174
|
+
}}
|
|
175
|
+
onAuthSuccess={(credentials) => {
|
|
176
|
+
// Optional: Send to analytics
|
|
177
|
+
analytics.track('DQM Auth Success');
|
|
178
|
+
}}
|
|
179
|
+
/>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Express.js Backend Example
|
|
185
|
+
|
|
186
|
+
Here's a complete Express.js backend example:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import express from 'express';
|
|
190
|
+
import axios from 'axios';
|
|
191
|
+
|
|
192
|
+
const app = express();
|
|
193
|
+
app.use(express.json());
|
|
194
|
+
|
|
195
|
+
// Simple token exchange (custom session-based)
|
|
196
|
+
app.post('/auth/token', async (req, res) => {
|
|
197
|
+
try {
|
|
198
|
+
// Verify user session (implement your own logic)
|
|
199
|
+
if (!req.session?.userId) {
|
|
200
|
+
return res.status(401).json({ error: 'Not authenticated' });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Fetch user's DQM credentials from your database
|
|
204
|
+
const user = await database.users.findById(req.session.userId);
|
|
205
|
+
|
|
206
|
+
res.json({
|
|
207
|
+
apiKey: user.dqmApiKey,
|
|
208
|
+
websiteId: user.dqmWebsiteId,
|
|
209
|
+
});
|
|
210
|
+
} catch (error) {
|
|
211
|
+
res.status(500).json({ error: 'Internal server error' });
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// OAuth2 callback handler
|
|
216
|
+
app.post('/auth/oauth2/callback', async (req, res) => {
|
|
217
|
+
const { code, redirectUri } = req.body;
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// Exchange authorization code for tokens
|
|
221
|
+
const tokenResponse = await axios.post('https://oauth.yourcompany.com/token', {
|
|
222
|
+
grant_type: 'authorization_code',
|
|
223
|
+
code,
|
|
224
|
+
redirect_uri: redirectUri,
|
|
225
|
+
client_id: process.env.OAUTH_CLIENT_ID,
|
|
226
|
+
client_secret: process.env.OAUTH_CLIENT_SECRET,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
const { access_token } = tokenResponse.data;
|
|
230
|
+
|
|
231
|
+
// Use access token to fetch user's DQM credentials
|
|
232
|
+
const userInfo = await axios.get('https://api.yourcompany.com/user/dqm-credentials', {
|
|
233
|
+
headers: { Authorization: `Bearer ${access_token}` },
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
res.json({
|
|
237
|
+
apiKey: userInfo.data.apiKey,
|
|
238
|
+
websiteId: userInfo.data.websiteId,
|
|
239
|
+
});
|
|
240
|
+
} catch (error) {
|
|
241
|
+
res.status(500).json({ error: 'OAuth2 flow failed' });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
app.listen(3000, () => {
|
|
246
|
+
console.log('DQM Auth Backend running on port 3000');
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Security Best Practices
|
|
251
|
+
|
|
252
|
+
1. **Never expose API keys in client-side code** for production
|
|
253
|
+
2. **Use HTTPS** for all authentication endpoints
|
|
254
|
+
3. **Implement CSRF protection** for OAuth2 flows
|
|
255
|
+
4. **Validate redirect URIs** in OAuth2 configuration
|
|
256
|
+
5. **Use short-lived sessions** and implement token refresh
|
|
257
|
+
6. **Log authentication events** for security monitoring
|
|
258
|
+
7. **Rate limit** authentication endpoints
|
|
259
|
+
|
|
260
|
+
## TypeScript Support
|
|
261
|
+
|
|
262
|
+
All configuration options are fully typed:
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
import type { DQMConfig, OAuth2Config } from '@crownpeak/dqm-react-component';
|
|
266
|
+
|
|
267
|
+
const config: DQMConfig = {
|
|
268
|
+
apiKey: '...',
|
|
269
|
+
websiteId: '...',
|
|
270
|
+
authBackendUrl: '...',
|
|
271
|
+
oauth2Config: {
|
|
272
|
+
authUrl: '...',
|
|
273
|
+
tokenUrl: '...',
|
|
274
|
+
clientId: '...',
|
|
275
|
+
redirectUri: '...',
|
|
276
|
+
scope: 'dqm:read',
|
|
277
|
+
},
|
|
278
|
+
useLocalStorage: true,
|
|
279
|
+
apiEndpoint: 'https://api.crownpeak.net/dqm-cms/v1', // Optional: custom endpoint
|
|
280
|
+
};
|
|
281
|
+
```
|