Headless WordPress Authentication with Native Cookies

Поділитися
Вставка
  • Опубліковано 22 лип 2024
  • Learn how to authenticate users on your decoupled, frontend JavaScript app using the same native auth cookies that WordPress uses.
    There's also a blog post for this video:
    developers.wpengine.com/blog/...
    Presenter: Kellen Mace - / kellenmace
    CONTENTS:
    00:00 - Intro
    00:56 - App Overview
    03:56 - Local Project Setup
    07:10 - How this Auth System Works
    09:45 - Security & HttpOnly Cookies
    11:24 - useAuth() Hook
    13:31 - AuthContent & UnAuthContent Components
    16:41 - Log In
    19:53 - Log Out
    22:36 - Navigation
    23:28 - Password Reset
    33:14 - New User Sign-up
    39:55 - User Profile
    43:55 - Create Post page
    49:48 - Shared Cookies & Admin Access
    54:26 - How to Use in Production
    55:39 - Outro
    CODE REPOS:
    Next.js app: github.com/kellenmace/headles...
    Port of the app to Gatsby.js: github.com/kellenmace/headles...
    PLUGIN LINKS:
    WPGraphQL: www.wpgraphql.com/
    WPGraphQL CORS: github.com/funkhaus/wp-graphq...
    Headless WordPress Email Settings: github.com/kellenmace/headles...
    Headless WordPress Admin Access: github.com/kellenmace/headles...
    DE{CODE} LINKS:
    Follow all of our content here: developers.wpengine.com
    DE{CODE} Twitter: / wpedecode

КОМЕНТАРІ • 61

  • @kellenmace3948
    @kellenmace3948 3 роки тому +10

    What questions do you have on implementing headless WordPress authentication using WP's native cookies? Let us know!

    • @kellenmace3948
      @kellenmace3948 2 роки тому +3

      @TOP 10 You can fire off a `viewer` GraphQL request from your Angular app, similar to the one I show at the 12:00 point in this video. If you get info about the user back in the response, you'll know they're logged in and can then fetch data or perform mutations meant for authenticated users in your Angular app. Thanks for watching! 👍

    • @josemariomega
      @josemariomega 2 роки тому +2

      Thanks for this detailed video, I have one question, I was trying to test my real production wordpress installation endpoint for the NEXT_PUBLIC_WORDPRESS_API_URL, but using the local front end app in next js, I'm getting the SUCCESS response in the network tab, but it seems that the cookie is not being set and app is not logging in. It's not possible to use a real domain graphql endpoint to test my local next js app authentication? Or am I missing some configuration?

    • @4mylife4mylove
      @4mylife4mylove Рік тому

      I'm getting "Failed to fetch" with CORS error when I logout, login works fine. It happens Gatsby app also. Any advice please?

  • @tby4242
    @tby4242 2 роки тому

    Thank you for the great explanations! This helped me out a lot!

  • @vilistahlberg1661
    @vilistahlberg1661 Рік тому +3

    In the video you appear to have the SameSite cookie attribute set to None which does make you vulnerable to CSRF attacks in this instance. However, I noticed that the WPGraphQL CORS plugin now allows the SameSite cookie mode to be set to Lax or Strict, which effectively eliminates CSRF threats.

  • @oramaboemmanuel473
    @oramaboemmanuel473 7 місяців тому

    Awesome Job on this project.

  • @islambn8962
    @islambn8962 9 місяців тому +2

    hey , any ideas on rest api ?
    seems like wp_set_auth_cookie uses lax mode
    so auth cookie does not set
    I did play with it to set the cookie but still
    functions like is_user_logged_in does not work

  • @mdst1
    @mdst1 2 роки тому +3

    Very nice and instructive video! Have you tried, by any chance, to implement ACF and update those fields in the profile with a mutation?

  • @jeromedicharry1340
    @jeromedicharry1340 10 місяців тому

    For those who get trouble in IOS, Safari etc...
    The first query (logIn) is sending the email / password as expected, but is not setting the auth cookie as it should do:
    As a consequence, the second refetchquery (getUser) is returning the following response:
    "data": {
    "viewer": null
    },
    This is because Apple doesn't allow cross-site cookies (related StackOverFlow thread)
    The short-term solution (for testing in dev mode on Safari) is to disable this option from Safari settings:
    Safari > Settings > Site tracking > Prevent Cross-Site Tracking.
    It will allow you to use the app, but it won't fix the issue for all other Safari / iOS users...
    The long-term solution is to host both the WordPress (back-end) & the webapp (front-end) on the same domain (e.g. each one on a different sub-domain).

  • @OptimusGrand
    @OptimusGrand 10 місяців тому

    Great video...i want to make windows desktop application for my wordpress website..can i do user athentication for that?

  • @gangernrahnge4309
    @gangernrahnge4309 Рік тому

    Can you show how we can do auth for fetching entries data form grafity form?

  • @jonadelsson3852
    @jonadelsson3852 2 роки тому

    Will this work on react-native (expo) app?

  • @davidgwyer5169
    @davidgwyer5169 4 місяці тому

    I'm looking to try out this method. Looks great. However, is the Safari issue with not allowing cross-site cookies still a problem? Would this prevent the headless site from being on a different domain?

  • @joshburgess817
    @joshburgess817 2 роки тому +1

    Love this video and want to try this out. I am still wrapping my head around microservice architecture and wondered if there is any benefit, or is it possible to break this into say a seperate nodejs rest api utilizing apollo and the graphql queries to handle auth and OAuth for your headless wordpress site? Thank you!

    • @kellenmace3948
      @kellenmace3948 2 роки тому +2

      Thanks Josh! Glad you found it helpful! Yeah, as an alternative to this approach, you could outsource authentication to a separate service, including a commercial service like auth0 if you wanted to.

  • @jeromedicharry1340
    @jeromedicharry1340 Рік тому

    this is fanttastic !!
    unfortunately this doesn't work when the wordpress is in a local installation (docker or local by flywheel)
    I don't know why viewer is alway null. Is there a know solution to set up local by flywheel for example ?
    the ting is i need to make some ajax request in wordpress so not easy to test with a production wordpress site

  • @iammukesh
    @iammukesh 2 роки тому +3

    Login is not working for me. wp_logged_in cookie not getting set as secure, samesite=none. any solution?

    • @vig221
      @vig221 2 роки тому

      same here

    • @josemariomega
      @josemariomega 2 роки тому

      Did you solve this? I'm having the same issue

    • @fabricec2074
      @fabricec2074 2 роки тому

      same here

    • @arellanojv1
      @arellanojv1 2 роки тому

      Same issue here. did you guys figure it out? Mark cross-site cookies as Secure to allow setting them in cross-site contexts

  • @IanMarkind
    @IanMarkind 3 роки тому +4

    Wow! This is really advancing headless WordPress.
    How difficult would it be to add 2-factor authentication with this setup? There are a handful of WordPress plugins for this

    • @kellenmace3948
      @kellenmace3948 3 роки тому +3

      Hey Ian! Great question- I'm not sure. I haven't set up 2FA myself for a WP site before (traditional or headless), so I'm not sure at this point. Please let me know if you get that working, though! I'd love to check out your implementation!

  • @bigj13310
    @bigj13310 3 роки тому +4

    How do you handle CSRF? By default when using cookie auth, WordPress adds a nonce to pages with forms and checks the nonce before returning data. Any cookie auth without a similar safeguard will be vulnerable to CSRF attacks.

    • @kellenmace3948
      @kellenmace3948 3 роки тому +5

      Hey @bigj13310 - Great question! As you likely already know, in traditional, monolithic WordPress sites, GET requests are used to trigger data create/update/delete operations in many cases, so someone could trick a logged-in user into visiting a URL, which would perform an action they didn't intend to cause. If you build a headless app that does the same, then implementing nonces to prevent CSRF attacks would be a good idea.
      In this example app, however, 100% of the GraphQL requests that modify data in WordPress are sent as POST requests, which are the result of a user performing some action, such as clicking a button. So a malicious actor tricking someone into simply visiting a URL (a GET request) would not result in any data mutations (which use POST requests) from being fired off. Further, that's not uncommon- standard practice with GraphQL is to send all requests as POST requests. That's what Apollo Client does by default for all requests, for example, unless you've explicitly configured it to do otherwise.
      Please let me know if you can think of anything else related to CSRF attacks that I haven't considered, though! Always willing to learn more and up my security game. 👍

    • @andrewjamesdawes
      @andrewjamesdawes 3 роки тому +2

      @@kellenmace3948 Even if the other (possibly malicious) URL was accessed via a GET request, couldn't scripts on that page still make malicious AJAX POST requests to your WordPress endpoints without you knowing? If the nonce is not required, then wouldn't these malicious requests be authorized by cookies alone (if sent with the POST request)?

    • @kellenmace3948
      @kellenmace3948 3 роки тому +1

      ​@@andrewjamesdawes A malicious actor could trick a user into navigating to a certain route in this app, but not into clicking any buttons that trigger data create/update/delete operations via a POST request. The user would have to knowingly click those buttons themselves.
      If there were rogue scripts running on the page (such as from a cross-site scripting (XSS) attack or a malicious browser extension), then anything is possible. Those rogue scripts could click buttons on the user's behalf on this website, or any other (their bank's website, their social media accounts, the admin dashboard of their WordPress site, etc.). That would be a much bigger security issue.

  • @richardvagel4505
    @richardvagel4505 3 роки тому +3

    Hi, is it possible to run this as a chrome extension without disabling http only?

    • @kellenmace3948
      @kellenmace3948 3 роки тому +1

      Hey Richard. I'm not sure what you mean. You shouldn't need a Chrome extension for this. I recommend having both the WP backend and the JS frontend served over https in production.

  • @dmarushchak
    @dmarushchak 2 роки тому +1

    I am always getting viewers: null after logging in, anyone knows what the problem might be? I haven't touched anything from the repo aside from the graphql url..

  • @HabitsAndRoutines
    @HabitsAndRoutines Рік тому

    I cloned your project, cannot query GET_USER, as the viewer returns null, even after login. Can you please help me, i cannot comment on your blog article.

  • @kaurkaur7683
    @kaurkaur7683 Рік тому

    I want to use this authentication can i use it at nodejs server?? If yes how?? And how do i get the wordpress logged in user cookie? I want to use that cookie for other api's route at my node server?? Is it possible? Or any other idea please suggest its urgent..

    • @WPEngineBuilders
      @WPEngineBuilders  Рік тому

      Hi Kaur- Yes, you can set and get cookies in Node.js. This article shows how to access them in Express, for example: www.geeksforgeeks.org/how-to-access-http-cookie-in-node-js/.

  • @Hackbandito
    @Hackbandito 3 роки тому +2

    Hi! Is it possible to check whether or not the user is logged in on server side? With getServerSideProps in nextjs?

    • @bigj13310
      @bigj13310 3 роки тому +2

      yes, by forwarding the cookies from the request headers

    • @Hackbandito
      @Hackbandito 3 роки тому +2

      @@bigj13310 How would I go about doing that?

    • @kellenmace3948
      @kellenmace3948 3 роки тому +2

      @@Hackbandito This approach would add a lot of complexity to your app. You have to authenticate the user once on the initial page load from the Next.js server -> WP server, then authenticate them again from the browser -> WP server for all subsequent requests, and set up cookie forwarding. I would only do that if you really need SSR for some reason. For my apps, I prefer to do this:
      Statically render all pages in Next.js (SSG). For any protected/gated content that the page may have, show a skeleton screen momentarily while a request is fired off to get the data from the WP backend. If the user is logged in and has the permissions necessary to view that content, then pop it into the UI. If the user was not logged in or did not have the permissions necessary to view that content, then programmatically redirect them to the Log In page, or show a "You don't have access to view this content" message.
      Having the initial page load be SSG allows that page to be distributed across a CDN so user's get a very fast initial load (much faster than SSR) and gives you great Core Web Vitals scores. Authenticated users only have to see a skeleton/loading screen briefly before they see the content appears. And it also makes your authentication setup much simpler. Would that work for your app?

    • @Hackbandito
      @Hackbandito 3 роки тому +2

      @@kellenmace3948 I see your point, but this would kinda defeat the main feature of NextJS, which is serverside rendered pages.

    • @kellenmace3948
      @kellenmace3948 3 роки тому +1

      ​@@Hackbandito A few years ago when CSR and SSR were the only options, I would have agreed with you. Since Next.js now supports SSG and ISR however, I use those whenever possible to statically render the "app shell" (any content that's the same for all users) and distribute those static pages across a CDN, then fetch any gated content via a client-side request.
      Another thing to think about is that even if you do SSR on the initial page load, you still have to fetch data from the client for any subsequent pages the user navigates to that contain gated content.
      I'm certainly not trying to dissuade you from doing SSR, though! Just sharing how I approach things. If SSR is a better choice for your app for one reason or another, then go for it! 😊

  • @gabuhl9509
    @gabuhl9509 Рік тому

    Thank you for the great explanations! I have implemented the login and it works but it doesn't work on IOS mobile devices, any clues why? am trying to debug it but no solutions yet.

    • @Selfnrj
      @Selfnrj Рік тому

      Have you found a solution for this?

    • @jeromedicharry1340
      @jeromedicharry1340 Рік тому

      hey if you can share your solutiuon... in safari doesn't work for me either. viewer returns null even if login is successfull

  • @spencerbigum1309
    @spencerbigum1309 2 роки тому +2

    I just setup this new native cooke method locally on my machine and I have one issue. When I login with the frontend, everything works fine. When I login using my backend first, and try to refresh the frontend page, I end up with viewer: null. Any ideas? Thanks for the awesome walkthrough on everything else, learned a ton.

    • @kellenmace3948
      @kellenmace3948 2 роки тому +2

      Hey Spencer! That is strange. I'm not sure offhand why you would be getting `null` for `viewer` if the user is logged in and the cookie is still valid. Were you able to get to the bottom of this issue? Thanks for watching! I'm glad the video was helpful! 👍

    • @spencerbigum1309
      @spencerbigum1309 2 роки тому

      @@kellenmace3948 Thx! I ended up figuring it out, I wasn't passing the cookie along in the response so I kept getting null - oops! Lol Thanks again for this great tutorial!

    • @HabitsAndRoutines
      @HabitsAndRoutines Рік тому

      @@spencerbigum1309 Hey did you resolve it?

    • @spencerbigum1309
      @spencerbigum1309 Рік тому

      @@HabitsAndRoutines I was able to get this working with Next Js, but I was not able to get it working with Remix if I recall. Remix would not read a secure cookie from another site on the server. It could only be done in the browser, which I think is why Next JS was able to do it.

    • @HabitsAndRoutines
      @HabitsAndRoutines Рік тому

      @@spencerbigum1309 did you need extra package or something? How did it resolved.

  • @simbaclaws_youtube
    @simbaclaws_youtube Рік тому

    From 13:50 you are making a point where you got some "top secret" content in your nextjs application. But shouldn't this information be fetched from an api with proper auth instead? Hardcoding secret info isn't a good way of doing things because people can just dig into the client side javascript code to figure out what the top secret content was....
    In the case of "router guarding", the only guard you are creating is client sided.
    Unless nextJS is actually fetching this info from something like getStaticProps, or getServerSideProps? Which is server side code for nextJS...
    EDIT: I posted this before hearing 15:20....

  • @preet-fm8rs
    @preet-fm8rs Рік тому

    I have used this authentication in reactjs its working fine i got the cookie ..now i want to send that cookie to the nodejs server in order to secure my nodejs server api's how do i send the cookie from reactjs??
    In my nodejs server i am not getting the cookie.I have noticed that the cookie having key something like wordpress_logged_in_189675588665788 and its value is the one which provides the user info. Please let me know how to get it ASAP??