Replies: 3 comments 6 replies
-
Thank you for this detailed write up! Hope it helps others... |
Beta Was this translation helpful? Give feedback.
-
hey, thats a really great writeup, the nginx config really helped out, I did auth a little differently, I am using React Query for server-side state, so instead context its more hooks based and that actually simplified auth a lot. I just had a couple of questions:
|
Beta Was this translation helpful? Give feedback.
-
I edited the post (see the bottom of my post for update 2024-08-22). Adding support for a custom user's session (not usersession) serializer and also adding functionality "post_save", which was actually really difficult to figure out for me since i'm not as familiar with django's @signal functionality. I tried to use those first, but never received any of the callbacks for headless, socialaccount, or account. maybe someone else has experience with that would could share. |
Beta Was this translation helpful? Give feedback.
-
First off, thank you so much to @pennersr for this amazing react-spa example and anyone else that has contributed to it. Honestly a phenomenal real-world application.
To dive right in, there were some initial hiccups porting this over for my own needs and I wanted to share.
One thing you might note down below is... the version number for django-allauth is 64.0.0... that is not a typo. Not sure what the cause of that was, but the previous release was 0.63.2 I believe... so, just note that incase you have a missing dep.
SETUP
Required Modules
django conf
This was all I needed to get the SPA and Django working together. So, you don't need to go searching for others, there was one post I saw that recommened
path("accounts/", include("allauth.socialaccount.urls"))
but that didn't change my situation.Please note that some python endpoints in the example app are 'accounts' and the react SPA has routes with 'account', they might trip you up when you are diagnosing which app is sending you to which location. If it says
/account
that is a redirect to theCLIENT
and if it says/accounts
that is a call to theDJANGO
applicationsettings.py
These INSTALLED_APPS were all required to get things working
The middleware
"allauth.account.middleware.AccountMiddleware",
If you want to have authentication with django admin AND social, I BELIEVE you need both of these AUTHENTICATION_BACKENDS. When I removed
ModelBackend
I got auth issues.Regarding HEADLESS setup
This was all I needed assuming you are ONLY doing social providers and that's all I'm looking for. The django admin will handle emails for admins, but I want to keep any user auth out of my system if possible.
Set the redirect url. LOGIN_REDIRECT_URL is where django will redirect you after the "google" or other provider callback. Please correct me if I'm wrong.
Understand the relationship of SOCIALACCOUNT_PROVIDERS and standard ACCOUNTS
In your settings file, and explained in the documentation you are making some decisions about how existing accounts will work with social account emails that may ALREADY exist in your app.
The SOCIALACCOUNT_EMAIL_AUTHENTICATION = True I'm calling out because it hung me up for a long time until I realized what was happening. I was just getting sent back to my app without the isAuthenticated = true and there wasn't any indication as to WHY.
The example django app was working for me when I pointed my own React app to it, however my own django app kept failing to authorize me.
This is around the time I finally turned on verbose logging and realized that I needed this SOCIALACCOUNT_EMAIL_AUTHENTICATION or the user would conflict with my ... wait for it... EXISTING DJANGO ADMIN USER that had the SAME email address because I was testing GOOGLE. YAY! ... so ... logging FTW, but also, look into this property and understand the ramifications. It allows your users to be "trusted". I'm okay with it because we still have an final level of approval that requires human interaction, but none the less, this is the big win for me.
CORS and CSRF issues
This was a uuuuuuuge red-herring and had me looking through tons of docs to figure out why my react app was suddenly experiencing issues with this. Sometimes calls would get through and other times the error was totally swallowed by the framework.
The example uses Docker to spin up an example. But if you (like me) are stuck in the 2000s and you don't have a docker-ized local environment this is the first place you'll want to look.
All these Keys are not necessary to get this working and setting some of them will actually cause phantom issues
To just get the basic setup working, I HIGHLY recommend just using nginx to proxy some shared port like 3000 to your React App and Python app "backends". Once you have the app working, you can go back and mess around with CORS and CSRF tokens, but let's avoid that until the actual thing is set up. If you follow this stategy you'll just hit localhost:3000 on your browser and requests will be automatically forwarded to either you node instance running your react app on port 8000 or your django app running on port 8001. The ports don't matter, just make sure they are available and you put them in the correct place.
Here's an example config: (don't for get to restart nginx after)
DEBUGGING (when your situation isn't quite like mine)
Set Logging to FULL and watch those incoming requests
React App (front end)
It first, I copied over most of the files and then slimmed the whole thing down to basically an "Auth" feature within my app that contained. The following and that was everything i needed to make the whole thing work.
Here is the app entry point:
The other change you need to make is in lib/allauth.js if you are working with the SPA example. This is just a fix for the use of nginx or docker with one entrypoint at localhost:3000 and someway of differentiating calls to the API vs the React App. Once you have it running... you can remove this and go back to normal localhost ports, but don't forget that you still need to battle with CSRFtokens and CORS errors. I'll follow up when I'm done working it out.
Finally
I saw many django web and allauth examples, but no one seemed to write up a tutorial on React in a way that solved my issues. (well, nothing can solve my neurospicy-ness, but ... I digress). This is just a hope that if you are working through a react app and finding tons of issue that this might solve one or two of them for you.
Thank you to the authors of this React/Django Example app. It is incredibly awesome that this exists and I hope more people adopt AllAuth because of it.
EDIT (2024-08-22):
If you are trying to trigger anything on "post user create", I found it a little challenging to fully understand this, especially since I am not highly experienced in django and the @receiver signals don't seem to be as reliable as Rails' "post_save" callbacks that I'm used to. Even django says that in their docs.
So the implementation for "Post Save" is to use an "Adapter" and this is documented in the allauth docs, but i was honestly not as sure how to implement, so here is a working example for anyone stuck on this. In my case, I wanted to create a "user profile" for a use because it is recommended in django to store additional properties on the profile instead of polluting the User object.
First you create a custom adapter. I'm literally calling it CustomSocialAccountAdapter just because that helps remind me that this isn't a built-in class.
Then in your settings.py, you need to specify your custom SOCIALACCOUNT_ADAPTER
Originally I tried to use a custom UserManager and set
objects = CustomUserManager()
on the User model, but the "create_user" method was only getting triggered when I was generating a user via the User.objects.create(). It would trigger when I was generating users in my seed data, but not in my social account login. In case you're curious it looked like this (not the line where I try tocreate_user_profile(user)
:While the manager DID NOT work, the custom adapter did in-fact, work for me and actually, if you are wondering about that
CustomHeadlessAdapter
I mentioned earlier, I wanted my/_allauth/browser/v1/auth/session
to return more than just base user so I could immediately do some SPA configuration. Mostly I wanted to choose where to redirect someone who was an admin or approved member, as in my case, a user needs to give us MORE information before they are officially a member. Social accounts don't provide enough in all situations.So here is a
CustomHeadlessAdapter
that allows us to change how the session is represented. Please note my comment about possibly just using a custom serializer because all of this logic is technically used in other places, I just wanted to share this ASAP incase others were struggling. Cheers!and as I said above, don't forget to set:
Please ask any questions. I'm happy to answer any if you stumble upon this and want to know more.
Beta Was this translation helpful? Give feedback.
All reactions