Skip to content

Commit

Permalink
feat(astro): Introduce <AuthenticateWithRedirectCallback/> for cust…
Browse files Browse the repository at this point in the history
…om oath flows (#3719)
  • Loading branch information
wobsoriano authored Jul 16, 2024
1 parent 1453383 commit c92104e
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/short-otters-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/astro": patch
---

Introduce `<AuthenticateWithRedirectCallback/>` as an Astro and as a React component
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
import type { HandleOAuthCallbackParams } from '@clerk/types';
type Props = HandleOAuthCallbackParams
import { generateSafeId } from '@clerk/astro/internal';
const safeId = generateSafeId();
// TODO: Move this to a prop when we implement more control components.
const functionName = 'handleRedirectCallback';
---

<div data-clerk-function-id={`clerk-${functionName}-${safeId}`}></div>

<script is:inline define:vars={{ props: Astro.props, functionName, safeId }}>
/**
* Store the id and the props for the Astro component in order to invoice the correct Clerk function once clerk is loaded.
* The above is handled by `invokeClerkAstroJSFunctions`.
*
* TODO: This should be moved to a separate file once we implement more control components.
*/
const setOrCreatePropMap = ({ functionName, id, props }) => {
if (!window.__astro_clerk_function_props) {
window.__astro_clerk_function_props = new Map();
}

if (!window.__astro_clerk_function_props.has(functionName)) {
const _ = new Map();
_.set(id, props);
window.__astro_clerk_function_props.set(functionName, _);
}

window.__astro_clerk_function_props.get(functionName)?.set(id, props);
};

setOrCreatePropMap({
functionName,
id: safeId,
props,
});
</script>
1 change: 1 addition & 0 deletions packages/astro/src/astro-components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
export { default as SignedIn } from './control/SignedIn.astro';
export { default as SignedOut } from './control/SignedOut.astro';
export { default as Protect } from './control/Protect.astro';
export { default as AuthenticateWithRedirectCallback } from './control/AuthenticateWithRedirectCallback.astro';

/**
* Unstyled Components
Expand Down
2 changes: 2 additions & 0 deletions packages/astro/src/internal/create-clerk-instance.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { waitForClerkScript } from '../internal/utils/loadClerkJSScript';
import { $clerk, $csrState } from '../stores/internal';
import type { AstroClerkIntegrationParams, AstroClerkUpdateOptions } from '../types';
import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions';
import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components';
import { runOnce } from './run-once';

Expand Down Expand Up @@ -35,6 +36,7 @@ async function createClerkInstanceInternal(options?: AstroClerkIntegrationParams
$csrState.setKey('isLoaded', true);

mountAllClerkAstroJSComponents();
invokeClerkAstroJSFunctions();

clerkJSInstance.addListener(payload => {
$csrState.setKey('client', payload.client);
Expand Down
19 changes: 19 additions & 0 deletions packages/astro/src/internal/invoke-clerk-astro-js-functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { $clerk } from '../stores/internal';

/**
* Loop through any Astro component that has requested to invoke a function and invoke it with its respective props.
*/
const invokeClerkAstroJSFunctions = () => {
const functionNames = ['handleRedirectCallback'] as const;

functionNames.forEach(fnName => {
const elementsOfCategory = document.querySelectorAll(`[data-clerk-function-id^="clerk-${fnName}"]`);
elementsOfCategory.forEach(el => {
const id = el.getAttribute('data-clerk-function-id');
const props = window.__astro_clerk_function_props?.get(fnName)?.get(id!) ?? {};
void $clerk.get()?.[fnName]?.(props);
});
});
};

export { invokeClerkAstroJSFunctions };
2 changes: 2 additions & 0 deletions packages/astro/src/internal/run-once.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Clerk } from '@clerk/clerk-js';

import { invokeClerkAstroJSFunctions } from './invoke-clerk-astro-js-functions';
import { mountAllClerkAstroJSComponents } from './mount-clerk-astro-js-components';
import type { CreateClerkInstanceInternalFn } from './types';

Expand All @@ -19,6 +20,7 @@ const runOnce = (onFirst: CreateClerkInstanceInternalFn) => {

if (clerkJSInstance.loaded) {
mountAllClerkAstroJSComponents();
invokeClerkAstroJSFunctions();
}
return res(clerkJSInstance.loaded);
});
Expand Down
19 changes: 18 additions & 1 deletion packages/astro/src/react/controlComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { CheckAuthorizationWithCustomPermissions } from '@clerk/types';
import type { CheckAuthorizationWithCustomPermissions, HandleOAuthCallbackParams } from '@clerk/types';
import type { PropsWithChildren } from 'react';
import React from 'react';

import type { ProtectComponentDefaultProps } from '../types';
import { useAuth } from './hooks';
import type { WithClerkProp } from './utils';
import { withClerk } from './utils';

export function SignedOut(props: PropsWithChildren) {
const { userId } = useAuth();
Expand Down Expand Up @@ -83,3 +86,17 @@ export const Protect = ({ children, fallback, ...restAuthorizedParams }: Protect
*/
return authorized;
};

/**
* Use `<AuthenticateWithRedirectCallback/>` to complete a custom OAuth flow.
*/
export const AuthenticateWithRedirectCallback = withClerk(
({ clerk, ...handleRedirectCallbackParams }: WithClerkProp<HandleOAuthCallbackParams>) => {
React.useEffect(() => {
void clerk?.handleRedirectCallback(handleRedirectCallbackParams);
}, []);

return null;
},
'AuthenticateWithRedirectCallback',
);
1 change: 1 addition & 0 deletions packages/astro/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type AstroClerkCreateInstanceParams = AstroClerkIntegrationParams & { publishabl
declare global {
interface Window {
__astro_clerk_component_props: Map<string, Map<string, Record<string, unknown>>>;
__astro_clerk_function_props: Map<string, Map<string, Record<string, unknown>>>;
}
}

Expand Down

0 comments on commit c92104e

Please sign in to comment.