vuejs / vuefire

🔥 Firebase bindings for Vue.js
https://vuefire.vuejs.org
MIT License
3.81k stars 322 forks source link

Support Multi tenancy #1515

Open Stf-F opened 2 months ago

Stf-F commented 2 months ago

Reproduction

Reproduction on localhost below

Steps to reproduce the bug

VueFire is currently not tenants aware which leads to 500 errors.

On localhost with the auth emulator:

  1. Setup vuefire with sessionCookies: true
  2. Enable multi tenancy and create a tenant in GCP as per: https://cloud.google.com/identity-platform/docs/multi-tenancy-quickstart
  3. Add multi tenancy support in firebase auth as per: https://cloud.google.com/identity-platform/docs/multi-tenancy-authentication (full code below)
  4. SignIn using a tenant
  5. Error

app.vue

<script lang="ts" setup>
import {
  signInWithEmailAndPassword,
  createUserWithEmailAndPassword,
} from "firebase/auth";

const tenantId = "TENANT_ID";
const auth = useFirebaseAuth()!;

// 👇 commenting out the block below helps testing the difference in behaviour 

if (auth) {
  auth.tenantId = tenantId;
}

const reg_state = reactive({
  email: "",
  password: "",
});

const reg_submit = async (e: Event) => {
  e.preventDefault();
  const user = await createUserWithEmailAndPassword(
    auth!,
    reg_state.email,
    reg_state.password
  );
  console.log(user);
};

const sign_in_state = reactive({
  email: "",
  password: "",
});

const sign_submit = async (e: Event) => {
  e.preventDefault();
  const user = await signInWithEmailAndPassword(
    auth!,
    sign_in_state.email,
    sign_in_state.password
  );
  console.log(user);
};
</script>

<template>
  <div>
    <fieldset>
      <legend>Register</legend>
      <form @submit="reg_submit">
        <label for="name">Email:</label><br />
        <input
          type="email"
          id="email"
          name="email"
          v-model="reg_state.email"
        /><br />
        <label for="pwd">Password:</label><br />
        <input
          type="password"
          id="pwd"
          name="pwd"
          v-model="reg_state.password"
        />
        <input type="submit" name="submit" />
      </form>
    </fieldset>

    <fieldset>
      <legend>Login</legend>

      <form @submit="sign_submit">
        <label for="name">Email:</label><br />
        <input
          type="email"
          id="email_sign_in"
          name="email"
          v-model="sign_in_state.email"
        /><br />
        <label for="pwd">Password:</label><br />
        <input
          type="password"
          id="pwd_sign_in"
          name="pwd"
          v-model="sign_in_state.password"
        />
        <input type="submit" name="submit" />
      </form>
    </fieldset>
  </div>
</template>

nuxt.config.ts

export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: [
    "nuxt-vuefire",
  ],
  vuefire: {
    config: {
      apiKey: process.env.NUXT_FIREBASE_API_KEY,
      authDomain: process.env.NUXT_FIREBASE_AUTH_DOMAIN,
      projectId: process.env.NUXT_FIREBASE_PROJECT_ID,
      storageBucket: process.env.NUXT_FIREBASE_STORAGE_BUCKET,
      appId: process.env.NUXT_FIREBASE_APP_ID,
    },
    auth: {
      enabled: true,
      sessionCookie: true,
    },
  },
});

Expected behavior

Full support of multi tenancy for authentication and session cookies

Actual behavior

The __session endpoint currently returns a 500 error with the following message when trying to authenticate with a tenant

There is no user record corresponding to the provided identifier.

image

Which leads to this error:

FirebaseError: Firebase: Login blocked by user-provided method: [POST] "/api/__session": 500 Internal Server Error (auth/login-blocked)

image

Additional information

This bug only occurs when session cookies and tenants are combined. Either of these features work when not put together. Thanks

Stf-F commented 2 months ago

Hi @posva , having done a bit of digging and testing the issue comes from here: https://github.com/vuejs/vuefire/blob/2e81d21420637a711574c1820c7170c331dda57c/packages/nuxt/src/runtime/auth/api.session-verification.ts#L30

If that were replaced with something along the lines of:

  const tenantManager = getAdminAuth(adminApp).tenantManager();
  const adminAuth = tenantManager.authForTenant(xxxx);

Then the error would go away and the __session endpoint be able to set the session cookie. But this would likely require an update to the vuefire object to allow for the entry of a tenantId. I am happy to assist with the process but I don't trust myself enough to deliver on the code changes themselves. Let me know if you need anything else. Cheers

posva commented 2 months ago

Nice, thanks for the help! I'm currently busy with other stuff so feel free to give it a try in your own projects and open a PR with what you found. It could always be helpful in the future to add the feature