Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server App Not Logging In #8355

Closed
jdgamble555 opened this issue Jul 6, 2024 · 30 comments · Fixed by #8393
Closed

Server App Not Logging In #8355

jdgamble555 opened this issue Jul 6, 2024 · 30 comments · Fixed by #8393

Comments

@jdgamble555
Copy link

Operating System

n/a

Browser Version

n/a

Firebase SDK Version

10.12.3

Firebase SDK Product:

Auth

Describe your project's tooling

SvelteKit with Firebase - https://code.build/p/sveltekit-todo-app-with-firebase-C73xaa

Describe the problem

While running this function on a fresh login with a new token:

export const firebaseServer = async (request: Request) => {

    const authIdToken = request.headers.get('Authorization')?.split('Bearer ')[1];

    if (!authIdToken) {
        error(401, 'Not Logged In!');
    }

    const serverApp = initializeServerApp(firebase_config, {
        authIdToken
    });

    // auth
    const serverAuth = getAuth(serverApp);
    await serverAuth.authStateReady();

    if (serverAuth.currentUser === null) {
        error(401, 'Invalid Token');
    }

    // db
    const serverDB = getFirestore(serverApp);

    return {
        serverAuth,
        serverDB
    };
};

I get this error on my server logs:

"FirebaseServerApp could not login user with provided authIdToken: ",
"FirebaseError: Firebase: Error (auth/network-request-failed)."

I thought everything was working with:
#8299
Because I didn't get a compile error, but I didn't actually run these two lines:

const serverAuth = getAuth(serverApp);
await serverAuth.authStateReady();

So, my code was not using the login token to login.

I am running on Cloudflare, so I imagine this would be the same problem in Vercel Edge, NextJS Middleware, etc.

Is this due to a fetch problem?

J

Steps and code to reproduce issue

Here is my REPO. You could clone it and use it with any Firestore instance with open rules. Just configure the .env file. It would need to be deployed to an edge environment.

https://github.com/jdgamble555/sveltekit-firebase-deploy

@jdgamble555 jdgamble555 added new A new issue that hasn't be categoirzed as question, bug or feature request question labels Jul 6, 2024
@jdgamble555
Copy link
Author

Possibly related to - #8347

@jbalidiong jbalidiong added api: auth needs-attention and removed new A new issue that hasn't be categoirzed as question, bug or feature request labels Jul 8, 2024
@DellaBitta
Copy link
Contributor

That's interesting. FirebaseServerApp uses the same standard networking calls as the other Auth operations. Any chance you could test any other standard Auth methods after Auth has been initialized?

@jdgamble555
Copy link
Author

I can't pinpoint this problem. It does seem to work on Vercel Edge, but not on Cloudflare, which is interesting considering Vercel Edge is just a Cloudflare Worker.

The About Page uses the Login:

Part of the problem is that there is no way to catch the real error. It just prints the error to the server console. I can only check for currentUser or fail.

import { PUBLIC_FIREBASE_CONFIG } from "$env/static/public";
import { error } from "@sveltejs/kit";
import { initializeServerApp } from "firebase/app";
import { getAuth } from "firebase/auth";
import { getFirestore } from "firebase/firestore/lite";

const firebase_config = JSON.parse(PUBLIC_FIREBASE_CONFIG);


export const firebaseServer = async (request: Request) => {

    const authIdToken = request.headers.get('Authorization')?.split('Bearer ')[1];

    if (!authIdToken) {
        error(401, 'Not Logged In!');
    }

    const serverApp = initializeServerApp(firebase_config, {
        authIdToken
    });

    // auth
    const serverAuth = getAuth(serverApp);
    await serverAuth.authStateReady();

    if (serverAuth.currentUser === null) {
        error(401, 'Invalid Token');
    }

    // db
    const serverDB = getFirestore(serverApp);

    return {
        serverAuth,
        serverDB
    };
};

I'm also wondering how Firebase knows it is using an authorized domain on the server? The request object is the only way to get the domain, and Firebase requires you to authorize each domain for a login... Perhaps Vercel works differently than Cloudflare on this front?

Any ideas?

Thanks,

J

@jimmy0251
Copy link

I am also facing the same issue. initializeServerApp working fine everywhere but fails on cloudflare edge.

@jdgamble555
Copy link
Author

jdgamble555 commented Jul 21, 2024

@DellaBitta - I made a minimum test project for Cloudflare.

https://github.com/jdgamble555/svelte-firebase-server-test
https://svelte-firebase-server-test.pages.dev/

  1. Create test FB project (or use existing)
    a. Make sure Login with Google is enabled
    b. Create test document (make sure it is readable VIA rules)
/about/ZlNJrKd6LcATycPRmBPA
{
  description: "This information was fetched on the server and hydrated on the browser!",
  name: "Some Post Man!"
}

  1. Test Locally
    a. Clone project or Fork it (make sure it is on GH somewhere to deploy later)
    b. Create the .env file with your Firebase credentials PUBLIC_FIREBASE_CONFIG={"apiKey":...}
    c. Test the project locally with npm run dev
    d. Login with Google
    e. Click Load About with Token

You should get the document you just added. Instead of adding a service worker, I emulate it by passing the Bearer token manually to the endpoint for testing purposes.


  1. Deploy to Cloudflare
    a. Login to Cloudflare
    b. Under "Workers & Pages" click "Create" then "Pages Tab" and Connect your Git REPO
    c. Add the environment variables under PUBLIC_FIREBASE_CONFIG
    d. Deploy
    e. Make sure your new domain is added to FB (Authentication -> Settings -> Authorized Domains)
    f. Under your deployment in Cloudflare, go to Functions -> Begin log Stream (to catch errors)

You will see the problem at hand. The page will fail when you login and click "Load About with Token"

Again, you wouldn't have to view server logs if there were a way to catch the actual error.

J

@DellaBitta
Copy link
Contributor

As a quick check, could you please see if other Auth operations such as signInAnonymously or signInWithEmailAndPassword succeed? I'm trying to discern if this is a general Auth usage error with Cloudflare, or if this is specific to the automatic signing in of a user by FirebaseServerApp. The answer will change how we direct the support of the issue. Thanks!

@jdgamble555
Copy link
Author

The error message is caused from this line:

await serverAuth.authStateReady();

Again, there should be a way to catch this error on the front end instead of server logs, so please throw the errors correctly when debugging this as well.

J

@jimmy0251
Copy link

I think it's not caused by await serverAuth.authStateReady();. That function just waits for auth to finish but actual error occurs during the authentication itself.

@jimmy0251
Copy link

@DellaBitta Just tried signInAnonymously, same error.

Code

  console.log("initialing app");
  const firebaseServerApp = initializeApp(firebaseConfig);

  console.log("initializing auth");
  const auth = getAuth(firebaseServerApp);

  console.log("waiting for auth state");
  await auth.authStateReady();

  console.log("Logging in annoymously");
  try {
    const user = await signInAnonymously(auth);
    console.log("User", user);
  } catch (e) {
    console.error("Error signing in anonymously", e);
  }

Logs

    {
      "message": [
        "initialing app"
      ],
      "level": "log",
      "timestamp": 1721691654779
    },
    {
      "message": [
        "initializing auth"
      ],
      "level": "log",
      "timestamp": 1721691654779
    },
    {
      "message": [
        "waiting for auth state"
      ],
      "level": "log",
      "timestamp": 1721691654779
    },
    {
      "message": [
        "Logging in annoymously"
      ],
      "level": "log",
      "timestamp": 1721691654779
    },
    {
      "message": [
        "Error signing in anonymously",
        "FirebaseError: Firebase: Error (auth/network-request-failed)."
      ],
      "level": "error",
      "timestamp": 1721691654779
    },
@jdgamble555
Copy link
Author

You're still calling await auth.authStateReady(); in your code, that is what is causing the error message.

When I leave that out, I get a different error:

  const serverApp = initializeServerApp(firebase_config, {
      authIdToken
  });
  
  const serverAuth = getAuth(serverApp);
  
  await signInAnonymously(serverAuth);
FirebaseError: Firebase: Operations that alter the current user are not supported in conjunction
with FirebaseServerApp (auth/operation-not-supported-in-this-environment).

J

@jimmy0251
Copy link

@jdgamble555 await auth.authStateReady() just waits for authentication to finish. You can try replace it with following and you will still get the same error.

  function getCurrentUser(auth: Auth) {
    return new Promise((resolve, reject) => {
      const unsubscribe = auth.onAuthStateChanged((user) => {
        unsubscribe();
        resolve(user);
      }, reject);
    });
  }
  
  const auth = getAuth(firebaseServerApp);
  const currentUser = await getCurrentUser(auth);
  console.log("currentUser", currentUser);
@jdgamble555
Copy link
Author

@jimmy0251 - Exactly. What it does behind the scenes, apparently onAuthStateChanged on the server is what is causing the problem.

J

@jimmy0251
Copy link

@DellaBitta I did some debugging and it seems like the real error is
Error: The 'referrerPolicy' field on 'RequestInitializerDict' is not implemented.. Is that needed for server side fetch requests?

Sentry made a similar fix here getsentry/sentry-javascript#9200. (Issue link)

@DellaBitta
Copy link
Contributor

const serverApp = initializeServerApp(firebase_config, {
    authIdToken
});
  
const serverAuth = getAuth(serverApp);

await signInAnonymously(serverAuth);

I'm sorry folks. I should have pointed out that Auth, when initialized with an instance of FirebaseServerApp, doesn't support changing the user, and therefore doesn't support any signIn methods. I meant to ask to switch to using FirebaseApp and use something like signInAnonymously and see if that fails. That would help us to determine if Auth is generally failing or if it's only something in FirebaseServerApp that's the problem.

@DellaBitta
Copy link
Contributor

@DellaBitta I did some debugging and it seems like the real error is Error: The 'referrerPolicy' field on 'RequestInitializerDict' is not implemented.. Is that needed for server side fetch requests?

Sentry made a similar fix here getsentry/sentry-javascript#9200. (Issue link)

The Auth SDK does indeed set the referrerPolicy on all of its fetch requests (see here).

If this is what's causing the problem for Auth when using both FirebaseApp and FirebaseServerApp in Cloudflare workers then I can take information to the Auth team to ask if it can be removed. However, it would probably take some time to determine if that's a viable change -- it might be the case that referrerPolicy is a field that the Auth service requires and/or enforces.

@jdgamble555
Copy link
Author

I get the same error when using:

const app = initializeApp(firebase_config);

const auth = getAuth(app);

await signInAnonymously(auth);
FirebaseError: Firebase: Error (auth/network-request-failed).

Side note, on my Qwik Todo App version (using the same Firebase code), I'm getting this error when deploying to Vercel Edge (Cloudflare in background):

Error: Service auth is not available

This could be a different problem all together, but just noting it here in case it is related. I can make a minimum test project later if you need me to.

J

@jimmy0251
Copy link

@DellaBitta Yes, that's what causing the issue. I think the field is not required for server auth but maybe it's there because earlier the auth SDK was intended to work only in browsers.

Looking forward to seeing this fixed. This is blocking us from making several components server-rendered.

@DellaBitta
Copy link
Contributor

@jdgamble555,

Side note, on my Qwik Todo App version (using the same Firebase code), I'm getting this error when deploying to Vercel Edge (Cloudflare in background)

Originally you mentioned that Vercel Edge was working, here.

The About Page uses the Login:

https://sveltekit-firebase-deploy.pages.dev/ - Cloudflare (not working About Page)
https://sveltekit-firebase-deploy.vercel.app/ - Vercel Edge (which is Cloudflare - Working)

Is that not the case anymore?

Thanks!

@jdgamble555
Copy link
Author

Yes, Vercel Edge is working fine with SvelteKit. It just does not work with Qwik. I believe Qwik bundles a bit differently than SvelteKit, so not exactly sure why it doesn't work. I can do some more testing when I get home after work with a test app, but in case it is related, I wanted you to know the error message.

@DellaBitta
Copy link
Contributor

Hi @jdgamble555,

Good news / bad news. I followed your instructions to deploy a copy of your example project to Cloudflare. I tested both the use of FirebaseServerApp with Auth's signInWithPopup to sign in via the Google provider and FirebaseApp with Auth's signInAnonymously. Both worked straight away.

Was there something else that you configured in Cloudflare which could have caused your deployment to run on a specific worker configuration?

@jdgamble555
Copy link
Author

jdgamble555 commented Jul 23, 2024

@DellaBitta - I'm not sure what you mean. In order to fully test the app, you have to click on the Load About with Token and you should see the Firestore document if it were working correctly. You can test this locally to see how it should work.

Try it again with the updated code (I had modified it to test signInAnonymously and forgot to change the code back).

FirebaseServerApp should work with an idToken and await serverAuth.authStateReady();, not signInWithPopup.

J

@jimmy0251
Copy link

@DellaBitta Thanks for the investigation. Would it be possible for you to share the demo project you made? I want to look at its Cloudflare config and will try to deploy it in my account to see if it's an account-specific issue.

@DellaBitta
Copy link
Contributor

@jdgamble555 and @jimmy0251, after further tinkering and testing I was able to reproduce the problem with both FirebaseServerApp and FirebaseApp running on Cloudflare. I'll notify the Auth team to see if we can remove the referrerPolicy field.

@jimmy0251
Copy link

Any update or timeline on this? Not being able to run Firestore on next.js edge runtimes is a real blocker for us.

@jdgamble555
Copy link
Author

@DellaBitta - All you guys need to do is remove one line of code:

referrerPolicy: 'no-referrer',

Is this on the horizon?

I have a feeling there might be something else to fix after this, so we need to move forward to test it.

Thanks,

J

@jdgamble555
Copy link
Author

@jimmy0251 @DellaBitta - While the referrerPolicy is a big problem, it is not the only one.

I forgot in SvelteKit you can filter through all fetch requests, and hence remove the unwanted header with hooks.

import type { Handle } from "@sveltejs/kit";

export const handle: Handle = async ({ event, resolve }) => {

    const modifiedRequest = new Request(event.request.url, {
        method: event.request.method,
        headers: event.request.headers,
        body: event.request.body,
        redirect: event.request.redirect,
        credentials: event.request.credentials,
        referrer: event.request.referrer,
        mode: event.request.mode,
        cache: event.request.cache,
        integrity: event.request.integrity,
        keepalive: event.request.keepalive,
        signal: event.request.signal,
        referrerPolicy: undefined
    });

    const response = await resolve({
        ...event,
        request: modifiedRequest,
    });

    return response;
};

This solves the first problem, but now the currentUser is always equal to null, even when the authIdToken is clearly passed correctly. Again, one of the biggest problems with this new feature is the lack of error messages.

console.log(authIdToken);

const serverApp = initializeServerApp(firebase_config, {
    authIdToken
});

// auth
const serverAuth = getAuth(serverApp);
await serverAuth.authStateReady();

if (serverAuth.currentUser === null) {
    // this is ALWAYS true
    error(401, 'Invalid Token');
}

J

@DellaBitta
Copy link
Contributor

DellaBitta commented Sep 12, 2024

Hi @jdgamble555 and @jimmy0251,

We've made a buid that removes referrerPolicy if the SDK detects that it's running in a Cloudflare Worker (#8393). I've tested it by using Auth to sign in an anonymous user. While this operation failed before, it now works.

Could you try pinning your firebase version to 10.13.1-canary.16d62d4fa in your package.json file and see if it works for you, or if there are any other operations that subsequently fail?

forgot in SvelteKit you can filter through all fetch requests, and hence remove the unwanted header with hooks.

According to the SvelteKit hook documentation, handle only intercepts operations that hit the server side of your SvelteKit app. It doesn't affect the behaviors of network operations made to external services. In my testing I've found this to be true, too. Therefore I don't believe that using handle to remove referrerPolicy will affect the behavior of the Firebase SDK in its attempts to reach the Auth service. This might be why things are still failing in your App.

But thankfully we have a candidate for a fix in the canary build mentioned above. Please give it a try. Thanks!

@jdgamble555
Copy link
Author

@DellaBitta - This looks like this fixes the problem!

I guess you're right!

https://svelte-firebase-server-test.pages.dev/

Thanks,

J

@DellaBitta
Copy link
Contributor

Great news!

The change will be part of our next release. I'll update this issue when it's available.

@DellaBitta
Copy link
Contributor

Version 10.13.2 has been released! I'm going to close this issue for now. If you encounter any other problem please create a new issue and mention this one within it (if it's related).

Thanks folks!

@firebase firebase locked and limited conversation to collaborators Oct 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
5 participants