Closed favsss closed 3 years ago
I'm running into this as well. I can't verify idToken
s created by the emulator.
@favs-sama where are you running the admin code?
Right now verifyIdToken()
for auth emulator tokens only works inside the Functions emulator. This is out of a concern for security, short-circuiting verifyIdToken()
is obviously dangerous if it accidentally happens in production so right now we only allow it in the Functions emulator, which we can control fully.
@samtstern originally i'm running the admin code verifyIdToken()
in a backend prehandler function for handling user authorization; so, no i'm not running this inside a firebase function. although is there any other way to approach this kind of testing if currently verifyIdToken()
for auth emulator is only accessible via functions emulator?
@favs-sama yeah right now the only way to test this is inside the Functions emulator. We do want to change this eventually but it requires us to build in a more secure version of verifyIdToken()
that would be less dangerous to your server in the event of a configuration mistake!
So for now I'll consider this a feature request.
I've created b/172262218 to track this feature request internally
Also running into this. Will be watching this issue.
I changed the name of this issue to more accurately reflect the feature request and include the use case from #2770
I'd need to verify/decode the token with the emulator as well.
@favs-sama where are you running the admin code?
Right now
verifyIdToken()
for auth emulator tokens only works inside the Functions emulator. This is out of a concern for security, short-circuitingverifyIdToken()
is obviously dangerous if it accidentally happens in production so right now we only allow it in the Functions emulator, which we can control fully.
I was planing to use the auth emulator to do tests without some weird workarounds required at the moment. I think that this behaviour (or at least some imitation of it) should be implemented for testing purposes. This also should have been mentioned at the documentation, would have saved me some time haha
Does anyone have a workaround for this?
@samtstern just voicing my support for this - many, many engineers do not use https.callable and instead opt for express setups, myself included. Not being able to support this means that we have a lack of ability to test our client-server interaction through integration tests.
From an engineering perspective, shouldn't this be as easy as disabling the 'kid' claim check when a certain envvar is set to true (IE, an envvar that is only set when firebase is running emulator mode)? I don't particularly understand why this would be hard to facilitate.
@mjgerace we know how to do this, but we're being extra careful about security. If your production server ever got into a situation where it thought it should disable/skip ID token verification then you'd have a big problem!
In order to have something in time for the launch of the Auth Emulator we compromised on a simple solution in the Node.js Admin SDK that is only enabled inside the Functions emulator. We are actively working on a longer-term solution that we're happier with and when we finish it we will bring it to all of our Admin SDKs (Node, Java, Go, Python, etc) so that you can develop on your own server.
@samtstern this makes total sense - is there any timeline for this work? In the meantime, would it be bad for our team to set an env var (FIREBASE_EMULATOR=1 yarn jest {test_file}) and otherwise workaround the issue in my actual auth middleware?
So long as I can modify the verifyIdToken()
function, I could manually implement my suggested fix while I work on testing. Our app isn't in production and this would allow us to write tests without doing anything overly risky.
@mjgerace we never offer timelines but this is something we're actively working on, it's not on the backlog. If you want to work around this issue on your own server and you're confident you know how, go for it!
Does anyone have a workaround for this?
At the moment when I'm running tests i change NODE_ENV environment variable to "test" and, based on that, change the auth token checking code to use the decode function from 'jsonwebtoken' module instead of firebase auth
@samtstern Couldn't this be as simple as checking for the presence of the FIREBASE_AUTH_EMULATOR_HOST
environment variable? If you are using the auth emulator then it is safe to assume that you're not running in production (or you already have some very serious security issues).
@nicoburns we use the presence of that environment variable to redirect any outbound HTTP requests the Admin SDK makes to the Auth API. However verifying ID Tokens and creating session cookies are mostly local operations that do not touch the Auth API. So changing how they work just based on the presence of an env var would create the possibility of someone remotely short-circuiting your Admin server's security, something we really really want to avoid.
We're working on changes to how the Admin SDK handles these operations that will make it safer to fix this issue.
any updates on this?
The error seems to also happen despite using the Functions emulator - do you mean that it only works if verifyIdToken
is used within a https.callable
? I'm using Express in my Cloud Function instead
This restriction is now lifted as of Node.js Admin SDK v9.5.0. Happy verifying emulator tokens!
This restriction is now lifted as of Node.js Admin SDK v9.5.0. Happy verifying emulator tokens!
Is there anything special we need to do for the firebase-admin
to verify emulator tokens? I'm still getting the 'Firebase ID token has no "kid" claim.' error..
EDIT:
I found the issue.. I had to set the FIREBASE_AUTH_EMULATOR_HOST
env variable. However, when running in Docker, localhost doesn't work and you have to use a special url. The following works if you're doing tests in a docker image:
docker run -e FIREBASE_AUTH_EMULATOR_HOST='host.docker.internal:9099' -p 8088:8080 my-image
Hey all! Glad to here this landed in Node Admin SDK. Is there an issue where I can track when this lands in Java Admin SDK?
@athomasoriginal https://github.com/firebase/firebase-admin-java/issues/493 tracks the Java Admin SDK feature request.
@yuchenshi Let's update the Firebase documentation. It still says
When running in any other environment, such as Cloud Run or your own server, these tokens will be rejected by the Admin SDK.
ref: https://firebase.google.com/docs/emulator-suite/connect_auth#id_tokens
@vajahath We're updated the docs. Thanks for the heads up.
Hi. A silly question perhaps, but where does one set the FIREBASE_AUTH_EMULATOR_HOST environment variable? The documentation doesn't explicitly state it. In which file should it be set? Where should it be located? @Joebayld , you seem to have figured it out, so any advice would be really appreciated... :) Thanks!
Hi. A silly question perhaps, but where does one set the FIREBASE_AUTH_EMULATOR_HOST environment variable? The documentation doesn't explicitly state it. In which file should it be set? Where should it be located? @Joebayld , you seem to have figured it out, so any advice would be really appreciated... :) Thanks!
It's environment variable, you can set it globally in ~/.bash_profile or in terminal before firebase command:
FIREBASE_AUTH_EMULATOR_HOST=localhost:9099; firebase emulators:start
.
For convenience use something like https://www.npmjs.com/package/dotenv, to separate configurations.
Thanks @v-kiniv . Only I made it work by setting the variable on the dev script as opposed to the emulators script:
"dev": "FIREBASE_AUTH_EMULATOR_HOST=localhost:9099 next dev"
This still existing in my case ,
code: 'auth/argument-error',
message: 'Firebase ID token has no "kid" claim. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
i am using firebase latest :
"firebase-admin": "^9.11.0",
also set env. variable :
FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
const idToken="eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6InJvaGFuLmtoYWFuYWlvQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiYXV0aF90aW1lIjoxNjI3NTY5NDA3LCJ1c2VyX2lkIjoiQ2VmQXV6ZlFsdG4yWkN2V1dIYU9rWE82YmhOMCIsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicm9oYW4ua2hhYW5haW9AZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifSwiaWF0IjoxNjI3NTY5NDA3LCJleHAiOjE2Mjc1NzMwMDcsImF1ZCI6InNreWNybS0xYjYzOSIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9za3ljcm0tMWI2MzkiLCJzdWIiOiJDZWZBdXpmUWx0bjJaQ3ZXV0hhT2tYTzZiaE4wIn0.";
admin.auth().verifyIdToken(idToken).then((decodedToken) => {
console.log("decode token", decodedToken);
})
This still existing in my case ,
code: 'auth/argument-error', message: 'Firebase ID token has no "kid" claim. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
i am using firebase latest :
"firebase-admin": "^9.11.0",
also set env. variable :FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
const idToken="eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6InJvaGFuLmtoYWFuYWlvQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiYXV0aF90aW1lIjoxNjI3NTY5NDA3LCJ1c2VyX2lkIjoiQ2VmQXV6ZlFsdG4yWkN2V1dIYU9rWE82YmhOMCIsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicm9oYW4ua2hhYW5haW9AZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifSwiaWF0IjoxNjI3NTY5NDA3LCJleHAiOjE2Mjc1NzMwMDcsImF1ZCI6InNreWNybS0xYjYzOSIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9za3ljcm0tMWI2MzkiLCJzdWIiOiJDZWZBdXpmUWx0bjJaQ3ZXV0hhT2tYTzZiaE4wIn0."; admin.auth().verifyIdToken(idToken).then((decodedToken) => { console.log("decode token", decodedToken); })
Make sure you've updated firebase-tools
to the latest version:
npm i -g firebase-tools
This still existing in my case ,
code: 'auth/argument-error', message: 'Firebase ID token has no "kid" claim. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
i am using firebase latest :
"firebase-admin": "^9.11.0",
also set env. variable :FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
const idToken="eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJlbWFpbCI6InJvaGFuLmtoYWFuYWlvQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiYXV0aF90aW1lIjoxNjI3NTY5NDA3LCJ1c2VyX2lkIjoiQ2VmQXV6ZlFsdG4yWkN2V1dIYU9rWE82YmhOMCIsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicm9oYW4ua2hhYW5haW9AZ21haWwuY29tIl19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifSwiaWF0IjoxNjI3NTY5NDA3LCJleHAiOjE2Mjc1NzMwMDcsImF1ZCI6InNreWNybS0xYjYzOSIsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9za3ljcm0tMWI2MzkiLCJzdWIiOiJDZWZBdXpmUWx0bjJaQ3ZXV0hhT2tYTzZiaE4wIn0."; admin.auth().verifyIdToken(idToken).then((decodedToken) => { console.log("decode token", decodedToken); })
Make sure you've updated
firebase-tools
to the latest version:npm i -g firebase-tools
sorry ! it was my Bad , after set env. reload the console can help if some one else stuck in same situation. 😀😀
Any news on this for other SDKs? I'm developing with Go and came across this.
Not hard to bypass when you find this but takes an hour to figure out why and implement it
EDIT. Seems my problem was using old package. Firestore docs https://firebase.google.com/docs/firestore/quickstart#go tell to install the old GOPATH version and not /v4
Everyone Having issue make sure by using : export FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
for linux
before running your application , double check that set's on your env., Linux : printenv
will be helpful.
Any news on this for other SDKs? I'm developing with Go and came across this.
Not hard to bypass when you find this but takes an hour to figure out why and implement it
EDIT. Seems my problem was using old package. Firestore docs https://firebase.google.com/docs/firestore/quickstart#go tell to install the old GOPATH version and not /v4
Oh my! You're a life saver! Following the docs does lead go users right into this issue. Thanks for this. And thanks firebase team!
Is there an implementation (or merge) reference of the type of branching FIREBASE_AUTH_EMULATOR_HOST
is doing during jwt decoding of unsigned emulator tokens? AKA, I don't have a Admin SDK so decoding/verification fails so need to implement myself.
This is still happening to me.
I am logging the user in using the following piece of code in Swift:
Auth.auth().signIn(withEmail: email, password: password)
I am then passing in an ID token to the backend web call like so:
let userIDToken = try await signIn.result?.user.getIDToken() ?? ""
await web.webCall(endpoint: userIDToken)
Finally, I am using Express/Cloud Run on the backend and verifying my token like this:
let idToken = await admin.auth().verifyIdToken(req.body.idToken);
const uid = idToken.uid;
console.log(uid);
However, I am getting the following error message:
FirebaseAuthError: Firebase ID token has no "kid" claim. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.
When I go to that URL, it tells me to do exactly what Im doing, so what am I doing wrong?
@jalvini If you are having issues, can you file a new bug?
Even with the env var Im getting this error:
FirebaseAppError: Error while making request: connect ECONNREFUSED ::1:9099. Error code: ECONNREFUSED
Even with the env var Im getting this error:
FirebaseAppError: Error while making request: connect ECONNREFUSED ::1:9099. Error code: ECONNREFUSED
I had to change mine to 127.0.0.1:9099
vs localhost:9099
. However, I'm now having an issue where the firebase auth emulator cannot find the user corresponding to the identifier in the JWT.
FirebaseAuthError: There is no user record corresponding to the provided identifier.
any update on this for the go v4 sdk? is it safe to use "firebase.google.com/go" instead of v4?
I implemented like this:
async function getIdTokenByEmailAndPassword(email, password) {
const isRunningInEmulator = process.env.FIREBASE_AUTH_EMULATOR_HOST !== undefined;
let baseUrl = `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=${process.env.GOOGLE_API_KEY}`;
if(isRunningInEmulator){
baseUrl = `http://${process.env.FIREBASE_AUTH_EMULATOR_HOST}/identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${process.env.GOOGLE_API_KEY}`;
}
const data = {
email: email,
password: password,
returnSecureToken: true
};
try {
const response = await axios.post(baseUrl, data, {
headers: {
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
throw Error(error.response ? error.response.data.error.message : error.message);
}
}
async function getIdTokenByCustomToken(customToken) {
const isRunningInEmulator = process.env.FIREBASE_AUTH_EMULATOR_HOST !== undefined;
let baseUrl = `https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${process.env.GOOGLE_API_KEY}`;
if(isRunningInEmulator){
baseUrl = `http://${process.env.FIREBASE_AUTH_EMULATOR_HOST}/identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${process.env.GOOGLE_API_KEY}`;
}
const data = {
token: customToken,
returnSecureToken: true
};
try {
const response = await axios.post(baseUrl, data, {
headers: {
'Content-Type': 'application/json'
}
});
return response.data;
} catch (error) {
throw Error(error.response ? error.response.data.error.message : error.message);
}
}
[REQUIRED] Environment info
firebase-tools: 8.14.1
Platform: Windows 10
[REQUIRED] Test case
Currently emulating a scenario where a signed in user sends userToken from frontend and backend decoded this token and retrieves uid for fetching data from database.
[REQUIRED] Steps to reproduce
make sure that the following node packages are installed and firebase emulators for auth, firestore, and database are enabled:
[REQUIRED] Expected behavior
The userToken is decoded properly so that uid is extracted from the token for fetching data.
[REQUIRED] Actual behavior
It fails with Firebase ID token has no "kid" claim. The code is working normally except when using emulator.