是否可以在会话期间向 NextAuth 提供程序添加更多范围?

问题描述 投票:0回答:3

我目前正在使用 NextAuth 在我的应用程序中登录,并且希望在用户已登录时向其中添加更多范围,以便我可以使用 Google Fit API。

我一直在阅读 NextAuth 的文档并做了一些研究,但没有发现任何对当前 NextAuth v4 在此范围情况下有帮助的内容。

我当前的 Google 配置:

import NextAuth from 'next-auth';
import GoogleProvider from "next-auth/providers/google"

const GOOGLE_AUTHORIZATION_URL =
    'https://accounts.google.com/o/oauth2/v2/auth?' +
    new URLSearchParams({
        prompt: 'consent',
        access_type: 'offline',
        response_type: 'code'
    })

export default NextAuth({
    // Configure one or more authentication providers
    providers: [
        GoogleProvider({
            clientId: process.env.GOOGLE_CLIENT_ID,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET,
            authorization: GOOGLE_AUTHORIZATION_URL,
        }),
  ],
callbacks: {
        async jwt({ token, user, account }) {
            // Initial sign in
            if (account && user) {
                return {
                    accessToken: account.access_token,
                    accessTokenExpires: Date.now() + account.expires_in * 1000,
                    refreshToken: account.refresh_token,
                    user
                }
            }

            // Return previous token if the access token has not expired yet
            if (Date.now() < token.accessTokenExpires) {
                return token
            }

            // Access token has expired, try to update it
            return refreshAccessToken(token)
        },
        async session({ session, token }) {
            session.user = token.user;
            session.accessToken = token.accessToken
            session.error = token.error
            return session
        }
    },
jwt: {
        secret: process.env.NEXTAUTH_JWT_SECRET,
    },
    secret: process.env.NEXTAUTH_SECRET,
})


async function refreshAccessToken(token) {
    try {
        const url =
            "https://oauth2.googleapis.com/token?" +
            new URLSearchParams({
                client_id: process.env.GOOGLE_CLIENT_ID,
                client_secret: process.env.GOOGLE_CLIENT_SECRET,
                grant_type: "refresh_token",
                refresh_token: token.refreshToken,
            })

        const response = await fetch(url, {
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
            },
            method: "POST",
        })

        const refreshedTokens = await response.json()

        if (!response.ok) {
            throw refreshedTokens
        }

        return {
            ...token,
            accessToken: refreshedTokens.access_token,
            accessTokenExpires: Date.now() + refreshedTokens.expires_at * 1000,
            refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // Fall back to old refresh token
        }
    } catch (error) {
        console.log(error)

        return {
            ...token,
            error: "RefreshAccessTokenError",
        }
    }
}

我当前的代码工作得很好,所以我只需要授权和使用 Google Fitness API 的范围。

next.js google-api google-oauth google-fit next-auth
3个回答
1
投票

只需要求用户使用附加范围再次重新验证自己即可。通过这个过程,重新验证,您将获得一个新的 access_token,它有足够的权限通过 Google Fitness API 进行 API 调用。

import {signin} from "next-auth/react"; 

const handleGrantAccess = async () => {   
    const res = await signIn('google', { callbackUrl: '/locations'}, 
             {prompt: "login", scope: "openid email profile 
             https://www.googleapis.com/auth/business.manage"});
}

希望对您有帮助。快乐编码。


0
投票

实际上让它工作了,在pages/api/auth/中创建了一个名为add_scopes.js的文件

export default (req, res) => {
    if (req.method === 'POST') {
        // construct the authorize URL with additional scopes
        const scopes = 'openid https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/fitness.activity.read https://www.googleapis.com/auth/fitness.location.read'
        const redirectUri = process.env.GOOGLE_CALLBACK_URL
        const clientId = process.env.GOOGLE_CLIENT_ID
        const authorizationUrl = `https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code&scope=${scopes}&redirect_uri=${redirectUri}&client_id=${clientId}`
        // send the authorization URL to the client
        res.json({ authorizationUrl });
    } else {
        res.status(405).end(); // Method Not Allowed
    }
}

然后做了一个按钮来调用这个api路由:

import { useCallback } from 'react';
import { Button }  from 'react-bootstrap';


const AddScopesButton = ({scopes=scopes}) => {
    const isAuthorized = scopes.includes("https://www.googleapis.com/auth/fitness.activity.read") && scopes.includes("https://www.googleapis.com/auth/fitness.location.read")
    const handleClick = useCallback(async () => {
        try {
            const res = await fetch("/api/auth/add_scopes", { method: "POST" });
            const json = await res.json()
            if (res.ok) {
                window.location.href = json.authorizationUrl;
            } else {
                throw new Error(res.statusText);
            }
        } catch (error) {
            console.error(error);
        }
    }, []);

    return (
        <>
            {!isAuthorized && (
                    <Button className='mt-2' onClick={handleClick}>Add Scopes</Button>
            )}
            {isAuthorized && <span>Authorized</span>}
        </>
    );
};

export default AddScopesButton;

唯一的问题是,如果您退出并重新登录,您需要再次获得授权,我真的很想知道是否有办法保存授权的 accessToken/范围。


0
投票

我有完全相同的问题,我需要获取 AzureAD user.read 范围和 api/api_scope 来从 api 获取数据,似乎无法找到一种方法来让获得访问权限的用户顺利完成此操作使用 AzureAD 登录。

您找到更好的方法来完成这项工作了吗?

© www.soinside.com 2019 - 2024. All rights reserved.