Skip to content

Commit 8e79ab7

Browse files
authored
Merge pull request #131 from authorizerdev/feat/open-id
Add open id authorization flow with PKCE
2 parents 5bf26f7 + 2bf6b8f commit 8e79ab7

File tree

114 files changed

+3461
-1431
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

114 files changed

+3461
-1431
lines changed

app/package-lock.json

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/App.tsx

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,33 @@ import React from 'react';
22
import { BrowserRouter } from 'react-router-dom';
33
import { AuthorizerProvider } from '@authorizerdev/authorizer-react';
44
import Root from './Root';
5+
import { createRandomString } from './utils/common';
56

67
export default function App() {
7-
// @ts-ignore
8-
const globalState: Record<string, string> = window['__authorizer__'];
8+
const searchParams = new URLSearchParams(window.location.search);
9+
const state = searchParams.get('state') || createRandomString();
10+
const scope = searchParams.get('scope')
11+
? searchParams.get('scope')?.toString().split(' ')
12+
: `openid profile email`;
13+
14+
const urlProps: Record<string, any> = {
15+
state,
16+
scope,
17+
};
18+
19+
const redirectURL =
20+
searchParams.get('redirect_uri') || searchParams.get('redirectURL');
21+
if (redirectURL) {
22+
urlProps.redirectURL = redirectURL;
23+
} else {
24+
urlProps.redirectURL = window.location.origin;
25+
}
26+
const globalState: Record<string, string> = {
27+
// @ts-ignore
28+
...window['__authorizer__'],
29+
...urlProps,
30+
};
31+
932
return (
1033
<div
1134
style={{
@@ -30,23 +53,15 @@ export default function App() {
3053
/>
3154
<h1>{globalState.organizationName}</h1>
3255
</div>
33-
<div
34-
style={{
35-
width: 400,
36-
margin: `10px auto`,
37-
border: `1px solid #D1D5DB`,
38-
padding: `25px 20px`,
39-
borderRadius: 5,
40-
}}
41-
>
56+
<div className="container">
4257
<BrowserRouter>
4358
<AuthorizerProvider
4459
config={{
4560
authorizerURL: window.location.origin,
4661
redirectURL: globalState.redirectURL,
4762
}}
4863
>
49-
<Root />
64+
<Root globalState={globalState} />
5065
</AuthorizerProvider>
5166
</BrowserRouter>
5267
</div>

app/src/Root.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,30 @@ const ResetPassword = lazy(() => import('./pages/rest-password'));
66
const Login = lazy(() => import('./pages/login'));
77
const Dashboard = lazy(() => import('./pages/dashboard'));
88

9-
export default function Root() {
9+
export default function Root({
10+
globalState,
11+
}: {
12+
globalState: Record<string, string>;
13+
}) {
1014
const { token, loading, config } = useAuthorizer();
1115

1216
useEffect(() => {
1317
if (token) {
14-
const url = new URL(config.redirectURL || '/app');
18+
let redirectURL = config.redirectURL || '/app';
19+
let params = `access_token=${token.access_token}&id_token=${token.id_token}&expires_in=${token.expires_in}&state=${globalState.state}`;
20+
if (token.refresh_token) {
21+
params += `&refresh_token=${token.refresh_token}`;
22+
}
23+
const url = new URL(redirectURL);
24+
if (redirectURL.includes('?')) {
25+
redirectURL = `${redirectURL}&${params}`;
26+
} else {
27+
redirectURL = `${redirectURL}?${params}`;
28+
}
29+
1530
if (url.origin !== window.location.origin) {
16-
window.location.href = config.redirectURL || '/app';
31+
sessionStorage.removeItem('authorizer_state');
32+
window.location.replace(redirectURL);
1733
}
1834
}
1935
return () => {};

app/src/index.css

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
body {
2-
margin: 0;
2+
margin: 10;
33
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
44
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
55
sans-serif;
@@ -14,3 +14,17 @@ body {
1414
*:after {
1515
box-sizing: inherit;
1616
}
17+
18+
.container {
19+
box-sizing: content-box;
20+
border: 1px solid #d1d5db;
21+
padding: 25px 20px;
22+
border-radius: 5px;
23+
}
24+
25+
@media only screen and (min-width: 768px) {
26+
.container {
27+
width: 400px;
28+
margin: 0 auto;
29+
}
30+
}

app/src/utils/common.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const getCrypto = () => {
2+
//ie 11.x uses msCrypto
3+
return (window.crypto || (window as any).msCrypto) as Crypto;
4+
};
5+
6+
export const createRandomString = () => {
7+
const charset =
8+
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~.';
9+
let random = '';
10+
const randomValues = Array.from(
11+
getCrypto().getRandomValues(new Uint8Array(43))
12+
);
13+
randomValues.forEach((v) => (random += charset[v % charset.length]));
14+
return random;
15+
};
16+
17+
export const createQueryParams = (params: any) => {
18+
return Object.keys(params)
19+
.filter((k) => typeof params[k] !== 'undefined')
20+
.map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k]))
21+
.join('&');
22+
};

dashboard/src/components/Menu.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ import {
2929
} from 'react-icons/fi';
3030
import { IconType } from 'react-icons';
3131
import { ReactText } from 'react';
32-
import { useMutation } from 'urql';
32+
import { useMutation, useQuery } from 'urql';
3333
import { NavLink, useNavigate, useLocation } from 'react-router-dom';
3434
import { useAuthContext } from '../contexts/AuthContext';
3535
import { AdminLogout } from '../graphql/mutation';
36+
import { MetaQuery } from '../graphql/queries';
3637

3738
interface LinkItemProps {
3839
name: string;
@@ -51,6 +52,7 @@ interface SidebarProps extends BoxProps {
5152

5253
export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
5354
const { pathname } = useLocation();
55+
const [{ fetching, data }] = useQuery({ query: MetaQuery });
5456
return (
5557
<Box
5658
transition="3s ease"
@@ -98,6 +100,19 @@ export const Sidebar = ({ onClose, ...rest }: SidebarProps) => {
98100
>
99101
<NavItem icon={FiCode}>API Playground</NavItem>
100102
</Link>
103+
104+
{data?.meta?.version && (
105+
<Text
106+
color="gray.600"
107+
fontSize="sm"
108+
textAlign="center"
109+
position="absolute"
110+
bottom="5"
111+
left="7"
112+
>
113+
Current Version: {data.meta.version}
114+
</Text>
115+
)}
101116
</Box>
102117
);
103118
};

dashboard/src/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export const LOGO_URL =
22
'https://user-images.githubusercontent.com/6964334/147834043-fc384cab-e7ca-40f8-9663-38fc25fd5f3a.png';
33

44
export const TextInputType = {
5+
CLIENT_ID: 'CLIENT_ID',
56
GOOGLE_CLIENT_ID: 'GOOGLE_CLIENT_ID',
67
GITHUB_CLIENT_ID: 'GITHUB_CLIENT_ID',
78
FACEBOOK_CLIENT_ID: 'FACEBOOK_CLIENT_ID',
@@ -25,6 +26,7 @@ export const TextInputType = {
2526
};
2627

2728
export const HiddenInputType = {
29+
CLIENT_SECRET: 'CLIENT_SECRET',
2830
GOOGLE_CLIENT_SECRET: 'GOOGLE_CLIENT_SECRET',
2931
GITHUB_CLIENT_SECRET: 'GITHUB_CLIENT_SECRET',
3032
FACEBOOK_CLIENT_SECRET: 'FACEBOOK_CLIENT_SECRET',

dashboard/src/graphql/queries/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
export const MetaQuery = `
2+
query MetaQuery {
3+
meta {
4+
version
5+
client_id
6+
}
7+
}
8+
`;
9+
110
export const AdminSessionQuery = `
211
query {
312
_admin_session{
@@ -9,6 +18,8 @@ export const AdminSessionQuery = `
918
export const EnvVariablesQuery = `
1019
query {
1120
_env{
21+
CLIENT_ID,
22+
CLIENT_SECRET,
1223
GOOGLE_CLIENT_ID,
1324
GOOGLE_CLIENT_SECRET,
1425
GITHUB_CLIENT_ID,

dashboard/src/layouts/AuthLayout.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { Box, Center, Flex, Image, Text } from '@chakra-ui/react';
1+
import { Box, Flex, Image, Text, Spinner } from '@chakra-ui/react';
22
import React from 'react';
3-
import { LOGO_URL } from '../constants';
3+
import { useQuery } from 'urql';
4+
import { MetaQuery } from '../graphql/queries';
45

56
export function AuthLayout({ children }: { children: React.ReactNode }) {
7+
const [{ fetching, data }] = useQuery({ query: MetaQuery });
68
return (
79
<Flex
810
flexWrap="wrap"
@@ -23,9 +25,18 @@ export function AuthLayout({ children }: { children: React.ReactNode }) {
2325
</Text>
2426
</Flex>
2527

26-
<Box p="6" m="5" rounded="5" bg="white" w="500px" shadow="xl">
27-
{children}
28-
</Box>
28+
{fetching ? (
29+
<Spinner />
30+
) : (
31+
<>
32+
<Box p="6" m="5" rounded="5" bg="white" w="500px" shadow="xl">
33+
{children}
34+
</Box>
35+
<Text color="gray.600" fontSize="sm">
36+
Current Version: {data.meta.version}
37+
</Text>
38+
</>
39+
)}
2940
</Flex>
3041
);
3142
}

dashboard/src/pages/Auth.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
useToast,
77
VStack,
88
Text,
9-
Divider,
109
} from '@chakra-ui/react';
1110
import React, { useEffect } from 'react';
1211
import { useMutation } from 'urql';

0 commit comments

Comments
 (0)