Аутентификация Google с помощью django-allauth не работает из-за ошибки "OAuth2Error: Invalid id_token"
Я пытаюсь настроить аутентификацию Google для моего веб-приложения DRF + Next.js. Я следую этому руководству . Я использую django-allauth 0.61.1
и dj-rest-auth 6.0.0
. Если я пытаюсь передать оба токена access
и id
:
...
const SIGN_IN_HANDLERS = {
credentials: async (user, account, profile, email, credentials) => {
return true;
},
google: async (user, account, profile, email, credentials) => {
try {
const response = await axios({
method: "post",
url: process.env.NEXTAUTH_BACKEND_URL + "auth/google/",
data: {
access_token: account["access_token"],
id_token: account["id_token"],
},
});
account["meta"] = response.data;
return true;
} catch (error) {
console.error(error);
return false;
}
},
};
const SIGN_IN_PROVIDERS = Object.keys(SIGN_IN_HANDLERS);
export const authOptions = {
pages: {
signIn: "/login",
},
secret: process.env.AUTH_SECRET,
session: {
strategy: "jwt",
maxAge: BACKEND_REFRESH_TOKEN_LIFETIME,
},
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {},
async authorize(credentials, req) {
console.log("here");
try {
const response = await axios({
url: process.env.NEXTAUTH_BACKEND_URL + "auth/login/",
method: "post",
data: credentials,
});
const data = response.data;
if (data) return data;
} catch (error) {
console.error(error);
}
return null;
},
}),
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
},
},
}),
],
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
if (!SIGN_IN_PROVIDERS.includes(account.provider)) return false;
return SIGN_IN_HANDLERS[account.provider](
user,
account,
profile,
email,
credentials
);
},
async jwt({ user, token, account }) {
if (user && account) {
let backendResponse =
account.provider === "credentials" ? user : account.meta;
token["user"] = user.user;
token["access_token"] = user.access;
token["refresh_token"] = user.refresh;
token["ref"] = getCurrentEpochTime() + BACKEND_ACCESS_TOKEN_LIFETIME;
return token;
}
if (getCurrentEpochTime() > token["ref"]) {
const response = await axios({
method: "post",
url: process.env.NEXTAUTH_BACKEND_URL + "auth/token/refresh/",
data: {
refresh: token["refresh_token"],
},
});
token["access_token"] = response.data.access;
token["refresh_token"] = response.data.refresh;
token["ref"] = getCurrentEpochTime() + BACKEND_ACCESS_TOKEN_LIFETIME;
}
return token;
},
async session({ token }) {
return token;
},
},
} satisfies NextAuthOptions;
Django возвращается с:
allauth.socialaccount.providers.oauth2.client.OAuth2Error: Invalid id_token
[23/Jun/2024 23:05:29] "POST /api/auth/google/ HTTP/1.1" 500
потому что не получается self.serializer.is_valid()
:
class GoogleLogin(SocialLoginView):
adapter_class = Adapter
callback_url = "http://127.0.0.1:3000/"
client_class = OAuth2Client
def post(self, request, *args, **kwargs):
self.request = request
self.serializer = self.get_serializer(data=self.request.data)
self.serializer.is_valid(raise_exception=True) # Fails here
self.login()
return self.get_response()
Если я попробую просто передать id_token
как access_token
, я получу:
allauth.socialaccount.providers.oauth2.client.OAuth2Error: Request to user info failed
[23/Jun/2024 23:11:58] "POST /api/auth/google/ HTTP/1.1" 500
Я читал интернет, и кажется, что у многих людей была эта проблема, и некоторые исправили ее, понизив до разных версий allauth и rest-auth, но ни одна из них не сработала для меня. Кто-нибудь знает, как правильно использовать Google authenticator с allauth? Мои настройки Django:
...
ALLOWED_HOSTS = ["127.0.0.1", "localhost"]
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.postgres",
"django.contrib.sites",
"rest_framework",
"rest_framework.authtoken",
"rest_framework_simplejwt",
"allauth",
"allauth.account",
"dj_rest_auth",
"dj_rest_auth.registration",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
"corsheaders",
"django_typomatic",
"users",
]
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"allauth.account.middleware.AccountMiddleware",
]
...
AUTHENTICATION_BACKENDS = [
"users.auth.EmailAuthBackend",
"allauth.account.auth_backends.AuthenticationBackend",
]
AUTH_USER_MODEL = "users.User"
CORS_ALLOW_ALL_ORIGINS = True
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": timedelta(days=7),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
"UPDATE_LAST_LOGIN": True,
"SIGNING_KEY": SECRET_KEY,
"ALGORITHM": "HS512",
}
SITE_ID = 1
# ACCOUNT_EMAIL_REQUIRED = True
# ACCOUNT_EMAIL_VERIFICATION = "mandatory"
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = "none"
ACCOUNT_EMAIL_UNKNOWN_ACCOUNTS = False
REST_AUTH = {
"USE_JWT": True,
"JWT_AUTH_HTTPONLY": False,
"USER_DETAILS_SERIALIZER": "users.serializers.UserSerializer",
}
SOCIALACCOUNT_PROVIDERS = {
"google": {
"APPS": [
{
"client_id": os.environ.get("AUTH_GOOGLE_ID"),
"secret": os.environ.get("AUTH_GOOGLE_SECRET"),
"key": "",
},
],
"SCOPE": [
"profile",
"email",
],
"AUTH_PARAMS": {
"access_type": "online",
},
"OAUTH_PKCE_ENABLED": True,
"VERIFIED_EMAIL": True,
}
}