Headless login with provider give cors error
Andrioden opened this issue · 4 comments
My use case is that I want to use allauth to help me authenticate with Discord and Google, i dont want my own users stored locally.
Previously i had this working using a form, but seeing i could simplify this with headless, i went for it.
HTML
<v-btn @click="login()" size="x-large" class="d-flex w-100">{{ type }}</v-btn>
JS
login: async function() {
await fetch("_allauth/browser/v1/auth/provider/redirect", {
method: "POST",
headers: {
"X-CSRFToken": Cookies.get("csrftoken"),
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
provider: this.type,
callback_url: "/account/logged-in/",
process: "login"
})
})
}
settings.py (relevant stuff)
ALLOWED_HOSTS = ["*"]
HEADLESS_FRONTEND_URLS = {
"account_confirm_email": "https://app.project.org/account/verify-email/{key}",
"account_reset_password_from_key": "https://app.org/account/password/reset/key/{key}",
"account_signup": "https://app.org/account/signup",
"socialaccount_login_error": "/ops-error",
}
AUTHENTICATION_BACKENDS = [
# Needed to log in by username in Django admin, regardless of `allauth`
"django.contrib.auth.backends.ModelBackend",
# `allauth` specific authentication methods, such as login by e-mail
"allauth.account.auth_backends.AuthenticationBackend",
]
SOCIALACCOUNT_PROVIDERS = {
"discord": {
"APP": config.oauth_discord,
},
"google": {
"APP": config.oauth_google,
"SCOPE": [
"profile",
"email",
],
"AUTH_PARAMS": {
"access_type": "online",
},
"OAUTH_PKCE_ENABLED": True,
},
}
Here is what happens
- Click button in web client, allauth api is called - OK
- allauth api responds with redirect - OK
- Discord redirect OPTIONS and GET - FAIL
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://discord.com/api/oauth2/authorize?client_id=1054551832501960765&redirect_uri=http%3A%2F%2F127.0.0.1%3A8000%2Faccount%2Fdiscord%2Flogin%2Fcallback%2F&scope=identify+email&response_type=code&state=O0vEMIUD4X5B0wdI. (Reason: header ‘x-csrftoken’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://discord.com/api/oauth2/authorize?client_id=1054551832501960765&redirect_uri=http%3A%2F%2F127.0.0.1%3A8000%2Faccount%2Fdiscord%2Flogin%2Fcallback%2F&scope=identify+email&response_type=code&state=O0vEMIUD4X5B0wdI. (Reason: CORS request did not succeed). Status code: (null).
Bonus question: Why do i need to send X-CSRFToken
?
"X-CSRFToken": Cookies.get("csrftoken"),
Without django logs Forbidden (CSRF token missing.): /_allauth/browser/v1/auth/provider/redirect
. I would image allauth could take care of all that?
You do not need to send X-CSRFToken
to pass the CSRF protection. Instead, you could attach the token to the request body.
login: async function() {
await fetch("_allauth/browser/v1/auth/provider/redirect", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
provider: this.type,
callback_url: "/account/logged-in/",
process: "login",
csrfmiddlewaretoken: Cookies.get("csrftoken")
})
})
}
Since Discord disallows that header, try this option. I think it should work.
See for example, the demo code.
This part from the docs is important:
As calling this endpoint results in a user facing redirect (302), this call is only available in a browser, and must be called in a synchronous (non-XHR) manner.
You are using fetch
-- just use a regular form POST (as in done in the demo code link above).
This part from the docs is important:
As calling this endpoint results in a user facing redirect (302), this call is only available in a browser, and must be called in a synchronous (non-XHR) manner.
You are using
fetch
-- just use a regular form POST (as in done in the demo code link above).
Thank you, the postForm worked. Yeah sorry, I read that documentation, but i didnt understand what non-XHR manner meant and didnt think to check it up.