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

SvelteKit+Auth.js集成Azure AD时缺失refresh_token问题

问题:SvelteKit 搭配 Auth.js 集成Azure AD无法获取refresh_token

在使用SvelteKit + Auth.js集成Azure AD时,仅能获取到access_token和id_token,无法拿到refresh_token,导致会话无法长期持久化。根据Azure AD官方文档的OAuth2授权码流说明,refresh_token是该流程的必需项。

以下是当前的配置代码:

import { SvelteKitAuth } from "@auth/sveltekit";
import AzureADProvider from "@auth/core/providers/azure-ad";
import { env as privateEnv } from "$env/dynamic/private";
import { env as publicEnv } from "$env/dynamic/public";
import type { HandleFetch } from "@sveltejs/kit";

async function refreshAccessToken(accessToken) {
  console.log("refreshAccessToken");
  try {
    const url = `https://login.microsoftonline.com/${privateEnv.AZURE_TENANT_ID}/oauth2/v2.0/token`;
    const req = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      body: `grant_type=refresh_token`
        + `&client_secret=${privateEnv.AZURE_CLIENT_SECRET}`
        + `&refresh_token=${accessToken.refreshToken}`
        + `&client_id=${privateEnv.AZURE_CLIENT_ID}`
    });
    const res = await req.json();
    console.log(res);
    return {
      ...accessToken,
      accessToken: res.access_token,
      accessTokenExpires: Date.now() + res.expires_in * 1000,
      refreshToken: res.refresh_token ?? accessToken.refreshToken
    };

  } catch (error) {
    console.log(error);

    return {
      ...accessToken,
      error: "RefreshAccessTokenError"
    };
  }
}

export const handle = SvelteKitAuth({
  providers: [
    //@ts-expect-error issue https://github.com/nextauthjs/next-auth/issues/6174
    AzureADProvider({
      clientId: privateEnv.AZURE_CLIENT_ID,
      clientSecret: privateEnv.AZURE_CLIENT_SECRET,
      tenantId: privateEnv.AZURE_TENANT_ID,
      authorization: {
        params: {
          scope: `openid profile email api://${privateEnv.AZURE_CLIENT_ID}/Test`
        }
      }
    })
  ],
  callbacks: {
    async jwt({ token, account }) {
      console.log("jwt callback");
      console.log(token);
      // Persist the OAuth access_token to the token right after signin
      if (account) {
        console.log("account");
        console.log(account);
        token.accessToken = account.access_token;
        token.accessTokenExpires = Date.now() + account.expires_in * 1000;
      }
      console.log(Date.now() + " " + token.accessTokenExpires);

      if (Date.now() < token.accessTokenExpires) {
        return token;
      }
      console.log("token expired, refreshing...");
      return refreshAccessToken(token);
    },
    async session({ session, token, user }) {
      // Send properties to the client, like an access_token from a provider.
      console.log(token);
      session.accessToken = token.accessToken;
      console.log("session callback");
      console.log(session);
      return session;
    }
  }
});
解决方案

1. 添加offline_access权限范围

Azure AD默认不会返回refresh_token,必须显式请求offline_access scope。修改AzureADProvider的authorization配置:

AzureADProvider({
  clientId: privateEnv.AZURE_CLIENT_ID,
  clientSecret: privateEnv.AZURE_CLIENT_SECRET,
  tenantId: privateEnv.AZURE_TENANT_ID,
  authorization: {
    params: {
      scope: `openid profile email offline_access api://${privateEnv.AZURE_CLIENT_ID}/Test`
    }
  }
})

2. 在JWT回调中保存refresh_token

当前代码没有将account中的refresh_token存入token,导致后续刷新时无法获取到refresh_token。修改jwt回调:

async jwt({ token, account }) {
  console.log("jwt callback");
  console.log(token);
  // Persist the OAuth access_token and refresh_token to the token right after signin
  if (account) {
    console.log("account");
    console.log(account);
    token.accessToken = account.access_token;
    token.accessTokenExpires = Date.now() + account.expires_in * 1000;
    // 新增:保存refresh_token
    token.refreshToken = account.refresh_token;
  }
  console.log(Date.now() + " " + token.accessTokenExpires);

  if (Date.now() < token.accessTokenExpires) {
    return token;
  }
  console.log("token expired, refreshing...");
  return refreshAccessToken(token);
}

3. 验证Azure AD应用注册配置

确保你的Azure AD应用注册是Web应用/API类型,并且在"身份验证"设置中不需要勾选"隐式授权和混合流"(授权码流无需此项),同时确认应用权限配置中包含offline_access(添加后需完成管理员同意流程)。

完成以上修改后,重新启动应用,登录后就能在account对象中拿到refresh_token,后续的token刷新逻辑可正常工作,实现会话的长期持久化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:05:45