Skip to content

Commit

Permalink
Authentication fixes/improvements (#3174)
Browse files Browse the repository at this point in the history
  • Loading branch information
apedroferreira authored Feb 7, 2024
1 parent 51b7c04 commit 79398e9
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 13 deletions.
2 changes: 1 addition & 1 deletion packages/toolpad-app/src/runtime/ToolpadApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1626,7 +1626,7 @@ export default function ToolpadApp({ rootRef, basename, state }: ToolpadAppProps
(window as any).toggleDevtools = () => toggleDevtools();
}, [toggleDevtools]);

const authContext = useAuth({ dom, basename });
const authContext = useAuth({ dom, basename, signInPagePath: `${basename}/signin` });

const appHost = useNonNullableContext(AppHostContext);
const showPreviewHeader: boolean = !!appHost.isPreview && !appHost.isCanvas;
Expand Down
23 changes: 18 additions & 5 deletions packages/toolpad-app/src/runtime/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const AUTH_SIGNOUT_PATH = `${AUTH_API_PATH}/signout`;

export type AuthProvider = 'github' | 'google' | 'azure-ad' | 'credentials';

function isResponseJSON(response: Response): boolean {
return response.headers.get('content-type')?.includes('application/json') || false;
}

export interface AuthSession {
user: {
name: string;
Expand Down Expand Up @@ -48,9 +52,10 @@ export const AuthContext = React.createContext<AuthPayload>({
interface UseAuthInput {
dom: appDom.RenderTree;
basename: string;
signInPagePath?: string;
}

export function useAuth({ dom, basename }: UseAuthInput): AuthPayload {
export function useAuth({ dom, basename, signInPagePath }: UseAuthInput): AuthPayload {
const authProviders = React.useMemo(() => {
const app = appDom.getApp(dom);
const authProviderConfigs = app.attributes.authentication?.providers ?? [];
Expand All @@ -71,7 +76,9 @@ export function useAuth({ dom, basename }: UseAuthInput): AuthPayload {
'Content-Type': 'application/json',
},
});
csrfToken = (await csrfResponse.json())?.csrfToken;
if (isResponseJSON(csrfResponse)) {
csrfToken = (await csrfResponse.json())?.csrfToken;
}
} catch (error) {
console.error((error as Error).message);
}
Expand Down Expand Up @@ -100,8 +107,10 @@ export function useAuth({ dom, basename }: UseAuthInput): AuthPayload {
setSession(null);
setIsSigningOut(false);

window.location.replace(`${basename}${AUTH_SIGNIN_PATH}`);
}, [basename, getCsrfToken]);
if (!signInPagePath || window.location.pathname !== signInPagePath) {
window.location.href = `${basename}${AUTH_SIGNIN_PATH}`;
}
}, [basename, getCsrfToken, signInPagePath]);

const getSession = React.useCallback(async () => {
setIsSigningIn(true);
Expand All @@ -115,7 +124,11 @@ export function useAuth({ dom, basename }: UseAuthInput): AuthPayload {
'Content-Type': 'application/json',
},
});
setSession(await sessionResponse.json());
if (isResponseJSON(sessionResponse)) {
setSession(await sessionResponse.json());
} else {
signOut();
}
} catch (error) {
console.error((error as Error).message);
signOut();
Expand Down
7 changes: 0 additions & 7 deletions packages/toolpad-app/src/server/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,6 @@ export function createAuthHandler(project: ToolpadProject): Router {
const googleProvider = GoogleProvider({
clientId: process.env.TOOLPAD_GOOGLE_CLIENT_ID,
clientSecret: process.env.TOOLPAD_GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: 'consent',
access_type: 'offline',
response_type: 'code',
},
},
});

const azureADProvider = AzureADProvider({
Expand Down
3 changes: 3 additions & 0 deletions packages/toolpad-app/src/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import { createRpcServer as createProjectRpcServer } from './projectRpcServer';
import { createRpcServer as createRuntimeRpcServer } from './runtimeRpcServer';
import { createAuthHandler, createRequireAuthMiddleware, getRequireAuthentication } from './auth';

// crypto must be polyfilled to use @auth/core in Node 18 or lower
globalThis.crypto ??= (await import('node:crypto')) as Crypto;

const currentDirectory = url.fileURLToPath(new URL('.', import.meta.url));

const DEFAULT_PORT = 3000;
Expand Down

0 comments on commit 79398e9

Please sign in to comment.