mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Disable OAuth in iframe (#701)
<!--
Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md
-->
<!-- ELLIPSIS_HIDDEN -->
----
> [!IMPORTANT]
> Disable OAuth in iframes using `useInIframe` hook and update
`SimpleTooltip` to support conditional disabling.
>
> - **Behavior**:
> - Disable OAuth buttons in iframes by using `useInIframe` hook in
`oauth-button.tsx`.
> - Show tooltip "OAuth is disabled in iFrame" when OAuth buttons are
disabled.
> - **Components**:
> - Add `useInIframe` hook in `use-in-iframe.tsx` to detect iframe
context.
> - Remove `IframePreventer` component and its usage in
`stack-handler.tsx`.
> - Update `SimpleTooltip` in `simple-tooltip.tsx` to accept `disabled`
prop to conditionally disable tooltips.
> - **Misc**:
> - Remove unused `useTranslation` import in `auth-page.tsx`.
>
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup>
for 35793e8055. You can
[customize](https://app.ellipsis.dev/stack-auth/settings/summaries) this
summary. It will automatically update as commits are pushed.</sup>
<!-- ELLIPSIS_HIDDEN -->
---------
Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
This commit is contained in:
parent
2d42f44483
commit
e6bf381e2f
@ -7,6 +7,7 @@ export function SimpleTooltip(props: {
|
||||
type?: 'info' | 'warning',
|
||||
inline?: boolean,
|
||||
className?: string,
|
||||
disabled?: boolean,
|
||||
}) {
|
||||
const iconClassName = cn("w-4 h-4 text-zinc-500", props.inline && "inline");
|
||||
const icon = props.type === 'warning' ?
|
||||
@ -21,7 +22,7 @@ export function SimpleTooltip(props: {
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<Tooltip open={props.disabled ? false : undefined}>
|
||||
<TooltipTrigger asChild>
|
||||
{props.inline ? (
|
||||
<span className={cn(props.className)}>
|
||||
|
||||
@ -42,8 +42,6 @@ export function AuthPage(props: Props) {
|
||||
}
|
||||
|
||||
function Fallback(props: Props) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<MaybeFullPage fullPage={!!props.fullPage}>
|
||||
<div className='stack-scope flex flex-col items-stretch' style={{ maxWidth: '380px', flexBasis: '380px', padding: props.fullPage ? '1rem' : 0 }}>
|
||||
|
||||
@ -4,7 +4,6 @@ import { getRelativePart } from "@stackframe/stack-shared/dist/utils/urls";
|
||||
import { RedirectType, notFound, redirect } from 'next/navigation'; // THIS_LINE_PLATFORM next
|
||||
import { useMemo } from 'react';
|
||||
import { SignIn, SignUp, StackServerApp } from "..";
|
||||
import { IframePreventer } from "../components/iframe-preventer";
|
||||
import { MessageCard } from "../components/message-cards/message-card";
|
||||
import { HandlerUrls, StackClientApp } from "../lib/stack-app";
|
||||
import { AccountSettings } from "./account-settings";
|
||||
@ -249,9 +248,7 @@ async function NextStackHandler<HasTokenStore extends boolean>(props: BaseHandle
|
||||
{next15DeprecationWarning}. This warning will not be shown in production.
|
||||
</span>
|
||||
)}
|
||||
<IframePreventer>
|
||||
{result}
|
||||
</IframePreventer>
|
||||
{result}
|
||||
</>;
|
||||
}
|
||||
|
||||
@ -317,11 +314,7 @@ function ReactStackHandler<HasTokenStore extends boolean>(props: BaseHandlerProp
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<IframePreventer>
|
||||
{result}
|
||||
</IframePreventer>
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
// END_PLATFORM
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
'use client';
|
||||
|
||||
import { BrandIcons, Button } from '@stackframe/stack-ui';
|
||||
import { BrandIcons, Button, SimpleTooltip } from '@stackframe/stack-ui';
|
||||
import Color from 'color';
|
||||
import { useEffect, useId, useState } from 'react';
|
||||
import { useStackApp } from '..';
|
||||
import { useTranslation } from '../lib/translations';
|
||||
import { useInIframe } from './use-in-iframe';
|
||||
|
||||
const iconSize = 22;
|
||||
|
||||
@ -27,6 +28,7 @@ export function OAuthButton({
|
||||
const { t } = useTranslation();
|
||||
const stackApp = useStackApp();
|
||||
const styleId = useId().replaceAll(':', '-');
|
||||
const isIframe = useInIframe();
|
||||
|
||||
const [lastUsed, setLastUsed] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
@ -167,28 +169,35 @@ export function OAuthButton({
|
||||
return (
|
||||
<>
|
||||
<style>{styleSheet}</style>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
localStorage.setItem('_STACK_AUTH.lastUsed', provider);
|
||||
await stackApp.signInWithOAuth(provider);
|
||||
}}
|
||||
className={`stack-oauth-button-${styleId} stack-scope relative`}
|
||||
<SimpleTooltip
|
||||
disabled={!isIframe}
|
||||
tooltip={isIframe ? "This auth provider is not supported in an iframe for security reasons." : undefined}
|
||||
className='stack-scope w-full inline-flex'
|
||||
>
|
||||
{!isMock && lastUsed === provider && (
|
||||
<span className="absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md">
|
||||
<Button
|
||||
onClick={async () => {
|
||||
localStorage.setItem('_STACK_AUTH.lastUsed', provider);
|
||||
await stackApp.signInWithOAuth(provider);
|
||||
}}
|
||||
className={`stack-oauth-button-${styleId} stack-scope relative w-full`}
|
||||
disabled={isIframe}
|
||||
>
|
||||
{!isMock && lastUsed === provider && (
|
||||
<span className="absolute -top-2 -right-2 bg-blue-500 text-white text-xs px-2 py-1 rounded-md">
|
||||
last
|
||||
</span>
|
||||
)}
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
{style.icon}
|
||||
<span className='flex-1'>
|
||||
{type === 'sign-up' ?
|
||||
</span>
|
||||
)}
|
||||
<div className='flex items-center w-full gap-4'>
|
||||
{style.icon}
|
||||
<span className='flex-1'>
|
||||
{type === 'sign-up' ?
|
||||
t('Sign up with {provider}', { provider: style.name }) :
|
||||
t('Sign in with {provider}', { provider: style.name })
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</Button>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</Button>
|
||||
</SimpleTooltip>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
'use client';
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function IframePreventer({ children }: {
|
||||
children: React.ReactNode,
|
||||
}) {
|
||||
export function useInIframe() {
|
||||
const [isIframe, setIsIframe] = useState(false);
|
||||
useEffect(() => {
|
||||
if (window.self !== window.top) {
|
||||
@ -11,9 +9,5 @@ export function IframePreventer({ children }: {
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (isIframe) {
|
||||
return <div>Stack Auth components may not run in an {'<'}iframe{'>'}.</div>;
|
||||
}
|
||||
|
||||
return children;
|
||||
return isIframe;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user