firebase-functions icon indicating copy to clipboard operation
firebase-functions copied to clipboard

sessionClaims content not getting added to the decoded token

Open patzj opened this issue 2 years ago • 6 comments

Related issues

N/A

[REQUIRED] Version info

node: 16.14.0

firebase-functions: 3.21.2

firebase-tools: 10.7.1

firebase-admin: 10.2.0

[REQUIRED] Test case

https://cloud.google.com/identity-platform/docs/blocking-functions#setting_custom_and_session_claims

Web App

export default function Home() {
  const { data: user } = useUser();
  const auth = getAuth();

  function signIn() {
    const provider = new GoogleAuthProvider();
    signInWithPopup(auth, provider).then(async (value) => {
      const idTokenResult = await value.user.getIdTokenResult(true);
      console.log(idTokenResult);
    });
  }

  if (!user) {
    return <button onClick={signIn}>Sign In</button>;
  }

  return (
    <div>
      <span>{user.displayName}</span>&nbsp;
      <button onClick={() => signOut(auth)}>Sign Out</button>
    </div>
  );
}

Cloud Function

export const authUserBeforeCreate = functions
  .region(region)
  .auth.user()
  .beforeCreate((user, context) => {
  // codes
  });
});

export const authUserBeforeSignIn = functions
  .region(region)
  .auth.user()
  .beforeSignIn(async (_, context) => {
    return {
      displayName: "Raging Tomato",
      sessionClaims: { signInIpAddress: context.ipAddress },
    };
  });
});

[REQUIRED] Steps to reproduce

The project was originally a GCP project and is using Identity Platform but I had to setup Firebase in it for various reasons.

  1. Deploy a beforeSignIn Cloud Function via firebase-tools
  2. In the web app, sign in the user using signInWithPopup from firebase/auth
  3. Print the idTokenResult
export const authUserBeforeCreate = functions
  .region(region)
  .auth.user()
  .beforeCreate((user, context) => {
  // codes
  });
});

export const authUserBeforeSignIn = functions
  .region(region)
  .auth.user()
  .beforeSignIn(async (_, context) => {
    return {
      displayName: "Raging Tomato",
      sessionClaims: { signInIpAddress: context.ipAddress },
    };
  });
});

[REQUIRED] Expected behavior

The sessionsClaims I returned from the beforeSignIn Cloud Function should be included in the decoded idToken

[REQUIRED] Actual behavior

Claims not getting added when I print the result of the codes below:

signInWithPopup(auth, provider).then(async (value) => {
  const idTokenResult = await value.user.getIdTokenResult(true);
  console.log(idTokenResult);
});

Were you able to successfully deploy your functions?

Yes. Also printing debug logs as expected.

patzj avatar Jun 08 '22 16:06 patzj

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

google-oss-bot avatar Jun 08 '22 16:06 google-oss-bot

Same happening for customClaims. It doesn't work. Can we get some help?

gorkamolero avatar Aug 24 '22 00:08 gorkamolero

We'll have a fix out soon (recently merged https://github.com/firebase/firebase-functions/pull/1199).

Thanks for your patience.

taeold avatar Aug 24 '22 00:08 taeold

As far as I can tell this is still broken. displayName overwrites correclty but any returned sessionClaims and customClaims are not available on the client. Has there been any progress on this issue? Thanks for any help you can provide.

zrthomas avatar Aug 27 '22 19:08 zrthomas

I found another bug that is possibly linked to this. I opened an issue for the same here: https://github.com/firebase/firebase-tools/issues/4946

DibyodyutiMondal avatar Sep 02 '22 14:09 DibyodyutiMondal

Putting this here - just in case it solves things for anyone like me:

  1. Use the gcip-cloud-functions library as recommended in https://cloud.google.com/identity-platform/docs/blocking-functions?hl=en (rather than the firebase-functions approach recommended in https://firebase.google.com/docs/auth/extend-with-blocking-functions)
  2. If you have to stick with firebase-functions, you can still set claims through the admin api eg.
const functions = require("firebase-functions")
const admin = require("firebase-admin")

admin.initializeApp()
exports.beforeSignIn = functions.auth.user().beforeSignIn((user, context) => {
    admin.auth().setCustomUserClaims(user.uid, {
        admin: true
    })
})

I'd recommend the using the identity platform library approach though

OVO-Josh avatar Dec 21 '22 13:12 OVO-Josh