You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Auth0 getAccessTokenSilently时遭遇frame-ancestors 'none' CSP错误

问题描述

用户会话过期后,调用getAccessTokenSilently获取新访问令牌时,触发以下错误:

Refused to frame 'https://****.uk.auth0.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'none'"

复现步骤

  • 让用户会话过期
  • 调用getAccessTokenSilently获取新的访问令牌
  • 控制台中观察到上述错误

相关代码

_app.tsx

import React from 'react';
import { Provider } from 'react-redux';
import { Auth0Provider, useAuth } from '@auth0/auth0-react';
import axios from 'axios';
import { ApiProvider } from './ApiProvider';
import { store } from './store';
import appConfig from './config';
import { handleOnRedirectCallback } from './auth';

const ApiProviderCustom = (props: ExtendedAppProps) => {
  const { Component, pageProps } = props;
  const { user, isAuthenticated, getAccessTokenSilently } = useAuth();

  const instance = axios.create();

  if (user && isAuthenticated) {
    instance.interceptors.request.use(
      async config => {
        const accessToken = await getAccessTokenSilently();
        config.headers.Authorization = `Bearer ${accessToken}`;
        return config;
      },
      error => Promise.reject(error)
    );
  }

  return (
    <ApiProvider instance={instance}>
      <Component {...pageProps} />
    </ApiProvider>
  );
};

const App = (props: ExtendedAppProps) => {
  return (
    <Provider store={store}>
      <Auth0Provider
        domain={appConfig.auth.CLIENT_DOMAIN}
        clientId={appConfig.auth.CLIENT_ID}
        authorizationParams={{
          audience: appConfig.auth.AUDIENCE,
          scope: appConfig.auth.SCOPE.replace(',', ' '),
          redirect_uri: typeof window !== 'undefined' ? window.location.origin : undefined,
        }}
        cacheLocation='localstorage'
        onRedirectCallback={handleOnRedirectCallback}
      >
        <ApiProviderCustom {...props} />
      </Auth0Provider>
    </Provider>
  );
};

export default App;

ApiContext.tsx

import { ReactNode, createContext } from 'react'
import { ApiContextType } from 'src/types/global'
import BackendApi from 'src/api/BackendApi'
import { useAuth } from 'src/hooks/useAuth'
import { isDefined } from 'src/utils/miscellaneous'
import { AxiosInstance } from 'axios'
import appConfig from 'src/configs/appConfig'

type Props = {
  instance: AxiosInstance
  children: ReactNode
}

const defaultProvider: ApiContextType = {
  backendApi: new BackendApi(undefined, appConfig.backend_base_url, undefined, appConfig.machine_learning_base_url)
}

const ApiContext = createContext(defaultProvider)

const ApiProvider = ({ instance, children }: Props) => {
  // ** Hooks
  const { user, isAuthenticated } = useAuth()

  if (isDefined(user) && isAuthenticated) {
    const authenticatedProvider: ApiContextType = {
      backendApi: new BackendApi(undefined, appConfig.backend_base_url, instance, appConfig.machine_learning_base_url)
    }

    return <ApiContext.Provider value={authenticatedProvider}>{children}</ApiContext.Provider>
  } else {
    return <ApiContext.Provider value={defaultProvider}>{children}</ApiContext.Provider>
  }
}

export { ApiContext, ApiProvider }

注:当前使用Auth0 Universal Login配置,问题与租户CSP设置的frame-ancestors 'none'指令直接相关。

问题原因

会话过期后,getAccessTokenSilently默认采用iframe静默授权方式获取新令牌,但Auth0租户的CSP规则frame-ancestors 'none'禁止任何页面嵌入该Auth0域名的iframe,因此触发权限错误。

解决方案

方案1:调整Auth0租户CSP设置

  1. 登录Auth0管理后台,进入目标租户
  2. 导航至Security > Content Security Policy
  3. 在frame-ancestors指令中添加你的应用域名(例如https://your-app-domain.com),修改后示例:
    frame-ancestors 'self' https://your-app-domain.com;
    
  4. 保存设置并等待生效

方案2:启用Refresh Token模式绕过iframe

通过配置useRefreshTokens让getAccessTokenSilently优先使用Refresh Token获取新令牌,完全避免iframe依赖:

  1. 先在Auth0应用设置中开启Refresh Token:
    • 进入应用的Advanced Settings > Grant Types,勾选Refresh Token
  2. 修改Auth0Provider配置:
    <Auth0Provider
      domain={appConfig.auth.CLIENT_DOMAIN}
      clientId={appConfig.auth.CLIENT_ID}
      authorizationParams={{
        audience: appConfig.auth.AUDIENCE,
        scope: appConfig.auth.SCOPE.replace(',', ' '),
        redirect_uri: typeof window !== 'undefined' ? window.location.origin : undefined,
      }}
      cacheLocation='localstorage'
      onRedirectCallback={handleOnRedirectCallback}
      useRefreshTokens={true} // 启用Refresh Token
      useRefreshTokensFallback={false} // 禁用iframe回退(可选)
    >
      <ApiProviderCustom {...props} />
    </Auth0Provider>
    

方案3:捕获错误并回退到显式登录

在axios拦截器中捕获CSP错误,引导用户重新登录:

  1. 在ApiProviderCustom中解构loginWithRedirect:
    const { user, isAuthenticated, getAccessTokenSilently, loginWithRedirect } = useAuth();
    
  2. 修改拦截器逻辑:
    instance.interceptors.request.use(
      async config => {
        try {
          const accessToken = await getAccessTokenSilently();
          config.headers.Authorization = `Bearer ${accessToken}`;
          return config;
        } catch (error) {
          // 识别iframe相关的CSP错误
          if (error instanceof Error && error.message.includes('frame-ancestors')) {
            await loginWithRedirect(); // 触发显式登录
          }
          return Promise.reject(error);
        }
      },
      error => Promise.reject(error)
    );
    

内容的提问来源于stack exchange,提问作者Parth Parmar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 08:35:08