Simplify authentication by leveraging CSR + CORS

Created on 3 May 2023, about 1 year ago
Updated 11 May 2024, about 1 month ago

Motivation

Currently authentication works with a shared cookie domain, e.g. both frontend and backend must be hosted below a common domain and the cookie must be configured to be set on the common base-domain. When setup, everything works easily, but still requires CORS setup to work for the authenticated API requests triggered by client-side navigation.

However, sometimes a common parent domain is not available or it is a security issue to use it since 3rd parties might be able to access it, e.g. this is often the case for development environments like *.gitpod.io or *.pantheon.io

Instead, we could solely rely on authentication API requests + disable SSR when the visitor is authenticated. SSR is not crucial for authenticated requests, since (SEO) bots and first-time hits are usually un-authenticated.

proposed resolution - Proxy API

Option Proxy-API:

  • Add route-rules for proxying /ce-api to the backend
  • Provide Drupal login form on /user/login in the frontend, so the cookie will be set in the frontend
  • People can / will have to login separately on frontend and backend
  • Optionally, also proxy files to go via the frontend, so the backend URL would not leak through at all

Originally proposed resolution

  • Set a cookie "active-session=1" after logging in. Thus must be done with-in nuxt somehow.
  • Add a route /user/login which checks the Drupal login state via "drupal/user/login_status?_format=json" and writes the cookie.
  • * When logged out, redirect to Drupal login with destination=/user/login
  • * When logged in, set the cookie and redirect to frontpage
  • Make nuxt3 setup disable SSR when a cookie with "active-session=1" is present

Option: Add session auto-detection:

  • After the first page load, check for a active-session cookie
  • If no cookie is there trigger a call to "drupal/user/login_status?_format=json" to determine whether the user is logged in
  • Set cookie with 1 when authentication was detected - valid with the browser session, else do not set a cookie. So a full page load always detects login state
πŸ“Œ Task
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡¦πŸ‡ΉAustria fago Vienna

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @fago
  • πŸ‡¦πŸ‡ΉAustria fago Vienna
  • πŸ‡¦πŸ‡ΉAustria fago Vienna

    On the frontend it should be possible to do it in nuxt3 as outlined here:

    You need to create a Nitro server middleware. Then you have a way to hook into every server request.
    The middleware function gets event as the first argument.
    Within the middleware function, you can use getCookie from h3 to check for your cookie.
    Then, based on that, you can set event.context.nuxt.noSSR to true.

    Untested code:

    // @/server/middleware/dynamic-no-ssr.ts
    
    export default defineEventHandler((event) => {
        const myCookie = getCookie(event, 'myCookie');
    
        if (myCookie) {
            event.context.nuxt = event.context.nuxt || {};
            event.context.nuxt.noSSR = true;
        }
    });
  • πŸ‡¦πŸ‡ΉAustria fago Vienna
  • πŸ‡¦πŸ‡ΉAustria fago Vienna

    Based upon the latest meeting with Dan and longwave we came up with two alternative solutions, leveraging nuxt proxying:

    Option Proxy-API:

    • Add route-rules for proxying /ce-api to the backend
    • Provide Drupal login form on /user/login in the frontend, so the cookie will be set in the frontend
    • People can / will have to login separately on frontend and backend
    • Optionally, also proxy files to go via the frontend, so the backend URL would not leak through at all

    Option Proxy-All:

    • The same as Proxy-API, but also proxy the editorial-experience (/admin) through the frontend.
    • The challenge here would be to ensure we get a complete list of to be-proxied-paths to the frontend, so the Drupal backend would work correctly.
    • People use the site only from the frontend domain, for adminitration and editing as well.

    It would be nice, if we could figure a way out to allow Drupal to return a list of to-be-proxied routes to nuxt.

  • πŸ‡¦πŸ‡ΉAustria fago Vienna

    Letting this sink, I think the option "Proxy API" is the way go here. For that we need to do https://github.com/drunomics/nuxtjs-drupal-ce/issues/165 and then provide the user-login on the frontend.

  • πŸ‡¦πŸ‡ΉAustria fago Vienna
  • πŸ‡ΊπŸ‡ΈUnited States glynster

    Would it make more sense to use a robust module on the Nuxt side for Auth?

    Such as:
    https://github.com/sidebase/nuxt-auth

    This way the communication, along with permissions and roles can be used?

  • πŸ‡¦πŸ‡ΉAustria fago Vienna

    @glynster: Thanks for your suggestion!

    I'm not a big fan of adding something like nuxt-auth in the frontend, since it complicates the frontend stack, e.g. it becomes harder to support multiple frontends, upgrade nuxt majors, etc. But that said, nothing would speak against supportin this optionally. The advantage would be that it makes the frontend aware of permissions via oauth scopes, right?
    Admin menu would definitely be a nice use-case, but in the end we only need a simple flag in page-api responses that tell us whether the users has backend-access/permission or not. Use-cases for permissions to check vary, so we could add a feature to allow permissions to be sent to the frontend as part of the page-api response. It smells a bit like a (simpler) rebuild of oauth-scopes though.
    Maybe let's add a feature request and work on supporting that in a dedicated ticket?

    As default, I think the cookie based access is fine, we just need to finish https://www.drupal.org/project/lupus_decoupled/issues/3336148 πŸ“Œ Add support for forms Needs review to have user-login forms on the frontend working.

  • πŸ‡ΊπŸ‡ΈUnited States glynster

    @fago I had actually thought of the permissions/roles being added to the API. I was thinking it makes sense to have a current_user section. Much like the response from /user/login. Then you have more flexibility and keeps things very simple. I agree with the complication of Nuxt Auth. As you say once the forms are connected I think this solves a lot of things. Then users can login from either end and all works as needed.

    As to the admin menu then you could have a welcome back or username along with a logout.

    Rock on for

    user-login forms on the frontend working
  • πŸ‡ΊπŸ‡ΈUnited States glynster

    FYI: We have managed to hook in Nuxt Auth for our use case. This enables clients to login through a general form using /user/login and user/logout. We use the rest api We also push the new cookie from the response header to the front end which keep font/back end in sync. As well as that we have a session with access to the standard user info. Within that session we have access to csrf_token so we could perform user/node updates if needed. So far so good!

Production build 0.69.0 2024