Skip to content

Commit 0ea56b5

Browse files
add missing openid routes (#201)
1 parent f309aeb commit 0ea56b5

11 files changed

Lines changed: 269 additions & 38 deletions

File tree

web/messages/en.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,10 @@
9898
"client_setup_mobile_forgot": "If you forgot to install the mobile app, click one of the buttons bellow.",
9999
"client_setup_mobile_google": "Google Play",
100100
"client_setup_mobile_apple": "Apple Store",
101-
"client_setup_footer_extra": "Once your Defguard client is configured, you can close this window."
101+
"client_setup_footer_extra": "Once your Defguard client is configured, you can close this window.",
102+
"openid_mfa_redirect_error_title": "Authentication Error",
103+
"openid_mfa_redirect_error_message": "No token provided in the URL. Please ensure you have a valid token to proceed with OpenID authentication.",
104+
"openid_mfa_redirect_error_missing_args": "Missing code or state in the callback's URL. The provider might not be configured correctly.",
105+
"openid_mfa_complete_title": "Authentication Completed",
106+
"openid_mfa_complete_subtitle": "You have been successfully authenticated. Please close this window and get back to the Defguard VPN Client"
102107
}

web/src/routeTree.gen.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ import { Route as IndexRouteImport } from './routes/index'
1919
import { Route as PasswordIndexRouteImport } from './routes/password/index'
2020
import { Route as PasswordSentRouteImport } from './routes/password/sent'
2121
import { Route as PasswordFinishRouteImport } from './routes/password/finish'
22+
import { Route as OpenidErrorRouteImport } from './routes/openid/error'
2223
import { Route as OpenidCallbackRouteImport } from './routes/openid/callback'
24+
import { Route as OpenidMfaIndexRouteImport } from './routes/openid/mfa/index'
25+
import { Route as OpenidMfaCallbackRouteImport } from './routes/openid/mfa/callback'
2326

2427
const TestRoute = TestRouteImport.update({
2528
id: '/test',
@@ -71,11 +74,26 @@ const PasswordFinishRoute = PasswordFinishRouteImport.update({
7174
path: '/password/finish',
7275
getParentRoute: () => rootRouteImport,
7376
} as any)
77+
const OpenidErrorRoute = OpenidErrorRouteImport.update({
78+
id: '/openid/error',
79+
path: '/openid/error',
80+
getParentRoute: () => rootRouteImport,
81+
} as any)
7482
const OpenidCallbackRoute = OpenidCallbackRouteImport.update({
7583
id: '/openid/callback',
7684
path: '/openid/callback',
7785
getParentRoute: () => rootRouteImport,
7886
} as any)
87+
const OpenidMfaIndexRoute = OpenidMfaIndexRouteImport.update({
88+
id: '/openid/mfa/',
89+
path: '/openid/mfa/',
90+
getParentRoute: () => rootRouteImport,
91+
} as any)
92+
const OpenidMfaCallbackRoute = OpenidMfaCallbackRouteImport.update({
93+
id: '/openid/mfa/callback',
94+
path: '/openid/mfa/callback',
95+
getParentRoute: () => rootRouteImport,
96+
} as any)
7997

8098
export interface FileRoutesByFullPath {
8199
'/': typeof IndexRoute
@@ -86,9 +104,12 @@ export interface FileRoutesByFullPath {
86104
'/session-end': typeof SessionEndRoute
87105
'/test': typeof TestRoute
88106
'/openid/callback': typeof OpenidCallbackRoute
107+
'/openid/error': typeof OpenidErrorRoute
89108
'/password/finish': typeof PasswordFinishRoute
90109
'/password/sent': typeof PasswordSentRoute
91110
'/password': typeof PasswordIndexRoute
111+
'/openid/mfa/callback': typeof OpenidMfaCallbackRoute
112+
'/openid/mfa': typeof OpenidMfaIndexRoute
92113
}
93114
export interface FileRoutesByTo {
94115
'/': typeof IndexRoute
@@ -99,9 +120,12 @@ export interface FileRoutesByTo {
99120
'/session-end': typeof SessionEndRoute
100121
'/test': typeof TestRoute
101122
'/openid/callback': typeof OpenidCallbackRoute
123+
'/openid/error': typeof OpenidErrorRoute
102124
'/password/finish': typeof PasswordFinishRoute
103125
'/password/sent': typeof PasswordSentRoute
104126
'/password': typeof PasswordIndexRoute
127+
'/openid/mfa/callback': typeof OpenidMfaCallbackRoute
128+
'/openid/mfa': typeof OpenidMfaIndexRoute
105129
}
106130
export interface FileRoutesById {
107131
__root__: typeof rootRouteImport
@@ -113,9 +137,12 @@ export interface FileRoutesById {
113137
'/session-end': typeof SessionEndRoute
114138
'/test': typeof TestRoute
115139
'/openid/callback': typeof OpenidCallbackRoute
140+
'/openid/error': typeof OpenidErrorRoute
116141
'/password/finish': typeof PasswordFinishRoute
117142
'/password/sent': typeof PasswordSentRoute
118143
'/password/': typeof PasswordIndexRoute
144+
'/openid/mfa/callback': typeof OpenidMfaCallbackRoute
145+
'/openid/mfa/': typeof OpenidMfaIndexRoute
119146
}
120147
export interface FileRouteTypes {
121148
fileRoutesByFullPath: FileRoutesByFullPath
@@ -128,9 +155,12 @@ export interface FileRouteTypes {
128155
| '/session-end'
129156
| '/test'
130157
| '/openid/callback'
158+
| '/openid/error'
131159
| '/password/finish'
132160
| '/password/sent'
133161
| '/password'
162+
| '/openid/mfa/callback'
163+
| '/openid/mfa'
134164
fileRoutesByTo: FileRoutesByTo
135165
to:
136166
| '/'
@@ -141,9 +171,12 @@ export interface FileRouteTypes {
141171
| '/session-end'
142172
| '/test'
143173
| '/openid/callback'
174+
| '/openid/error'
144175
| '/password/finish'
145176
| '/password/sent'
146177
| '/password'
178+
| '/openid/mfa/callback'
179+
| '/openid/mfa'
147180
id:
148181
| '__root__'
149182
| '/'
@@ -154,9 +187,12 @@ export interface FileRouteTypes {
154187
| '/session-end'
155188
| '/test'
156189
| '/openid/callback'
190+
| '/openid/error'
157191
| '/password/finish'
158192
| '/password/sent'
159193
| '/password/'
194+
| '/openid/mfa/callback'
195+
| '/openid/mfa/'
160196
fileRoutesById: FileRoutesById
161197
}
162198
export interface RootRouteChildren {
@@ -168,9 +204,12 @@ export interface RootRouteChildren {
168204
SessionEndRoute: typeof SessionEndRoute
169205
TestRoute: typeof TestRoute
170206
OpenidCallbackRoute: typeof OpenidCallbackRoute
207+
OpenidErrorRoute: typeof OpenidErrorRoute
171208
PasswordFinishRoute: typeof PasswordFinishRoute
172209
PasswordSentRoute: typeof PasswordSentRoute
173210
PasswordIndexRoute: typeof PasswordIndexRoute
211+
OpenidMfaCallbackRoute: typeof OpenidMfaCallbackRoute
212+
OpenidMfaIndexRoute: typeof OpenidMfaIndexRoute
174213
}
175214

176215
declare module '@tanstack/react-router' {
@@ -245,13 +284,34 @@ declare module '@tanstack/react-router' {
245284
preLoaderRoute: typeof PasswordFinishRouteImport
246285
parentRoute: typeof rootRouteImport
247286
}
287+
'/openid/error': {
288+
id: '/openid/error'
289+
path: '/openid/error'
290+
fullPath: '/openid/error'
291+
preLoaderRoute: typeof OpenidErrorRouteImport
292+
parentRoute: typeof rootRouteImport
293+
}
248294
'/openid/callback': {
249295
id: '/openid/callback'
250296
path: '/openid/callback'
251297
fullPath: '/openid/callback'
252298
preLoaderRoute: typeof OpenidCallbackRouteImport
253299
parentRoute: typeof rootRouteImport
254300
}
301+
'/openid/mfa/': {
302+
id: '/openid/mfa/'
303+
path: '/openid/mfa'
304+
fullPath: '/openid/mfa'
305+
preLoaderRoute: typeof OpenidMfaIndexRouteImport
306+
parentRoute: typeof rootRouteImport
307+
}
308+
'/openid/mfa/callback': {
309+
id: '/openid/mfa/callback'
310+
path: '/openid/mfa/callback'
311+
fullPath: '/openid/mfa/callback'
312+
preLoaderRoute: typeof OpenidMfaCallbackRouteImport
313+
parentRoute: typeof rootRouteImport
314+
}
255315
}
256316
}
257317

@@ -264,9 +324,12 @@ const rootRouteChildren: RootRouteChildren = {
264324
SessionEndRoute: SessionEndRoute,
265325
TestRoute: TestRoute,
266326
OpenidCallbackRoute: OpenidCallbackRoute,
327+
OpenidErrorRoute: OpenidErrorRoute,
267328
PasswordFinishRoute: PasswordFinishRoute,
268329
PasswordSentRoute: PasswordSentRoute,
269330
PasswordIndexRoute: PasswordIndexRoute,
331+
OpenidMfaCallbackRoute: OpenidMfaCallbackRoute,
332+
OpenidMfaIndexRoute: OpenidMfaIndexRoute,
270333
}
271334
export const routeTree = rootRouteImport
272335
._addFileChildren(rootRouteChildren)

web/src/routes/openid/callback.tsx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,33 @@ const schema = z.object({
1212
export const Route = createFileRoute('/openid/callback')({
1313
component: RouteComponent,
1414
validateSearch: schema,
15+
onError: () => {
16+
throw redirect({ to: '/enrollment-start', replace: true });
17+
},
1518
loaderDeps: ({ search }) => ({ search }),
1619
beforeLoad: async ({ search }) => {
17-
const openIdResponse = await api.openId.enrollmentCallback.callbackFn({
18-
data: {
19-
code: search.code,
20-
state: search.state,
21-
type: 'enrollment',
22-
},
23-
});
24-
const enrollmentStartResponse = await api.enrollment.start.callbackFn({
25-
data: {
26-
token: openIdResponse.data.token,
27-
},
28-
});
20+
const openIdResponse = await api.openId.enrollmentCallback
21+
.callbackFn({
22+
data: {
23+
code: search.code,
24+
state: search.state,
25+
type: 'enrollment',
26+
},
27+
})
28+
.catch((e) => {
29+
console.error(e);
30+
throw redirect({ to: '/enrollment-start', replace: true });
31+
});
32+
const enrollmentStartResponse = await api.enrollment.start
33+
.callbackFn({
34+
data: {
35+
token: openIdResponse.data.token,
36+
},
37+
})
38+
.catch((e) => {
39+
console.error(e);
40+
throw redirect({ to: '/enrollment-start', replace: true });
41+
});
2942
useEnrollmentStore.setState({
3043
enrollmentData: enrollmentStartResponse.data,
3144
token: openIdResponse.data.token,

web/src/routes/openid/error.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { createFileRoute } from '@tanstack/react-router';
2+
import { m } from '../../paraglide/messages';
3+
import { PageProcessEnd } from '../../shared/components/PageProcessEnd/PageProcessEnd';
4+
import { useOpenidStore } from '../../shared/hooks/useOpenIdStore';
5+
6+
export const Route = createFileRoute('/openid/error')({
7+
component: RouteComponent,
8+
});
9+
10+
function RouteComponent() {
11+
const openIdError = useOpenidStore(
12+
(s) => s.error ?? m.openid_mfa_redirect_error_message(),
13+
);
14+
15+
return (
16+
<PageProcessEnd
17+
title={m.openid_mfa_redirect_error_title()}
18+
subtitle={openIdError}
19+
icon="disabled"
20+
/>
21+
);
22+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { createFileRoute, redirect } from '@tanstack/react-router';
2+
import z from 'zod';
3+
import { m } from '../../../paraglide/messages';
4+
import { api } from '../../../shared/api/api';
5+
import { PageProcessEnd } from '../../../shared/components/PageProcessEnd/PageProcessEnd';
6+
import { useOpenidStore } from '../../../shared/hooks/useOpenIdStore';
7+
8+
const searchSchema = z.object({
9+
code: z.string().trim().min(1),
10+
state: z.string().trim().min(1),
11+
});
12+
13+
export const Route = createFileRoute('/openid/mfa/callback')({
14+
validateSearch: searchSchema,
15+
onError: () => {
16+
useOpenidStore.setState({ error: m.openid_mfa_redirect_error_missing_args() });
17+
throw redirect({ to: '/openid/error', replace: true });
18+
},
19+
loaderDeps: ({ search }) => ({ search }),
20+
loader: async ({ deps }) => {
21+
try {
22+
await api.openId.mfaCallback.callbackFn({
23+
data: {
24+
code: deps.search.code,
25+
state: deps.search.state,
26+
type: 'mfa',
27+
},
28+
});
29+
} catch (e) {
30+
console.error(e);
31+
}
32+
},
33+
component: RouteComponent,
34+
});
35+
36+
function RouteComponent() {
37+
return (
38+
<PageProcessEnd
39+
title={m.openid_mfa_complete_title()}
40+
subtitle={m.openid_mfa_complete_subtitle()}
41+
icon="check-circle"
42+
/>
43+
);
44+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { createFileRoute, redirect, useLoaderData } from '@tanstack/react-router';
2+
import { useEffect } from 'react';
3+
import z from 'zod';
4+
import { api } from '../../../shared/api/api';
5+
import { isPresent } from '../../../shared/defguard-ui/utils/isPresent';
6+
7+
const searchSchema = z.object({
8+
token: z.string().trim().min(1),
9+
});
10+
11+
export const Route = createFileRoute('/openid/mfa/')({
12+
component: RouteComponent,
13+
validateSearch: searchSchema,
14+
onError: () => {
15+
throw redirect({
16+
to: '/openid/error',
17+
replace: true,
18+
});
19+
},
20+
loaderDeps: ({ search }) => ({ search }),
21+
loader: async ({ deps }) => {
22+
const response = await api.openId.authInfo
23+
.callbackFn({
24+
data: {
25+
type: 'mfa',
26+
state: deps.search.token,
27+
},
28+
})
29+
.catch((e) => {
30+
console.error(e);
31+
throw redirect({
32+
to: '/openid/error',
33+
replace: true,
34+
});
35+
});
36+
if (!isPresent(response.data.url)) {
37+
console.error('Missing URL in server response.');
38+
throw redirect({
39+
to: '/openid/error',
40+
replace: true,
41+
});
42+
}
43+
return response.data.url as string;
44+
},
45+
});
46+
47+
function RouteComponent() {
48+
const loaderData = useLoaderData({
49+
from: '/openid/mfa/',
50+
});
51+
52+
useEffect(() => {
53+
if (loaderData) {
54+
window.location.href = loaderData;
55+
}
56+
}, [loaderData]);
57+
return null;
58+
}

0 commit comments

Comments
 (0)