I need help getting my Firebase Apollo/GraphQL Cloud Function to authenticate and receive query requests.
- I implemented an Apollo/GraphQL server as a Cloud Function in Firebase/Firestore using this repository from this post.
- I set permissions for the cloud function to
allAuthenticatedUsers
and I am using Firebase Phone Authentication to authenticate. - I used code from this stackoverflow answer to help structure the authentication portion not included in the initial repository.
The Apollo/GraphQL function works fine (tested with playground) when permissions are set to allUsers
. After setting permissions to allAuthenticatedUsers
and attempting to send authenticated queries I am receiving the following error response:
Bearer error="invalid_token" error_description="The access token could not be verified"
I believe I am making a mistake with the request sent by the client, and or the handling of the verification and "context" of the ApolloServer. I have confirmed the initial user token is correct. My current theory is that I am sending the wrong header, or messing up the syntax somehow at either the client or server level.
To explain what I believe the appropriate flow of the request should be:
- Token generated in client
- Query sent from client with token as header
- ApolloServer cloud function receives request
- Token is verified by Firebase, provides new verified header token
- Server accepts query with new verified header token and returns data
If anyone can explain how to send valid authenticated client queries to a Firebase Apollo/GraphQL Cloud Function the help would be greatly appreciated. Code for server and client below.
Server.js (ApolloServer)
/* Assume proper imports */
/* Initialize Firebase Admin SDK */
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "[db-url]",
});
/* Async verification with user token */
const verify = async (idToken) => {
var newToken = idToken.replace("Bearer ", "");
let header = await admin.auth().verifyIdToken(newToken)
.then(function(decodedToken) {
let uid = decodedToken.uid;
// Not sure if I should be using the .uid from above as the token?
// Also, not sure if returning the below object is acceptable, or
// if this is even the correct header to send to firebase from Apollo
return {
"Authorization": `Bearer ${decodedToken}`
}
}).catch(function(error) {
// Handle error
return null
});
return header
}
/* Server */
function gqlServer() {
const app = express();
const apolloServer = new ApolloServer({
typeDefs: schema,
resolvers,
context: async ({ req, res }) => {
const verified = await verify(req.headers.Authorization)
console.log('log verified', verified)
return {
headers: verified ? verified: '',
req,
res,
}
},
// Enable graphiql gui
introspection: true,
playground: true
});
apolloServer.applyMiddleware({app, path: '/', cors: true});
return app;
}
export default gqlServer;
Client.js (ApolloClient)
Client query constructed using these instructions.
/* Assume appropriate imports */
/* React Native firebase auth */
firebase.auth().onAuthStateChanged(async (user) => {
const userToken = await user.getIdToken();
/* Client creation */
const client = new ApolloClient({
uri: '[Firebase Cloud Function URL]',
headers: {
Authorization: userToken ? `Bearer ${userToken}` : ''
},
cache: new InMemoryCache(),
});
/* Query test */
client.query({
query: gql`
{
hello
}
`
}).then(
(result) => console.log('log query result', result)
).catch(
(error) => console.log('query error', error)
)
})
UPDATE 05/03/20
I may have found the source of the error. I won't post an answer until I confirm, but here's the update. Looks like allAuthenticatedUsers
is a role specific to Google accounts and not Firebase. See this part of the google docs and this stackoverflow answer.
I will do some testing but the solution may be to change the permissions to allUsers
which may still require authentication. If I can get it working I will update with an answer.
Bearer ${userToken}
? userToken : '' " Is this line correct? – gstvgAuthorization: Bearer ID_TOKEN
. So I think so yes. Docs for ref -cloud.google.com/functions/docs/securing/…, – Jason