Reputation: 3919
I have a React app that is making calls to an API. I have a Client component to handle the calls, and the Components can access it like this (this example is in the componentDidMount function of the Home page, where I want to get a list of all this user's items):
componentDidMount() {
let userId= this.context.userId;
var url = "items/getAllMyItems/" + userId;
Client.fetchData(url, data => {
this.setState({items: data});
});
}
The current setup has no security (just for testing purposes) and the Client is defined like this (this is index.js):
function fetchData(fetchPath, cb) {
return fetch(`https://api.url/${fetchPath}`, {accept: "application/json"})
.then(cb);
}
(there are a couple of other functions which check the results etc, but I've left them out for brevity).
Now, my app connects to Firebase for handling authentication. I have A Firebase component which has 3 files:
firebase.js:
import app from 'firebase/app';
import 'firebase/auth';
const config = {
apiKey: /* etc */,
};
class Firebase {
constructor() {
app.initializeApp(config);
this.auth = app.auth();
}
// *** Auth API ***
doSignInWithEmailAndPassword = (email, password) =>
this.auth.signInWithEmailAndPassword(email, password);
doSignOut = () => this.auth.signOut();
}
export default Firebase;
context.js:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
index.js:
import FirebaseContext, { withFirebase } from './context';
import Firebase from './firebase';
export default Firebase;
export { FirebaseContext, withFirebase };
We're now implementing backend security, and I need to pass the Firebase token to the API when making calls. I can't figure out how to do it properly.
I know I need to call
firebase.auth().currentUser.getIdToken(true).then(function(idToken) {
// API call with Authorization: Bearer `idToken`
}).catch(function(error) {
// Handle error
});
so I figured that Client/index.js would need to change to something like:
import react from 'react';
import { FirebaseContext } from '../Firebase';
function fetchData(fetchPath, cb) {
<FirebaseContext.Consumer>
{firebase => {
firebase.auth().currentUser.getIdToken(true)
.then(function(idToken) {
// API call with Authorization: Bearer `idToken`
return fetch(`https://api.url/${fetchPath}`, {accept: "application/json"})
.then(cb);
}).catch(function(error) {
// Handle error
});
}}
</FirebaseContext.Consumer>
}
but if I do this I get the error "Expected an assignment or function call but instead saw the expression". I realize this is because it's expecting me to return a component, but I don't want to do that as there's nothing to return. I also tried using useContext, and changing fetchData to:
const Client = () => {
const firebase = useContext(FirebaseContext);
firebase.auth().currentUser.getIdToken(true)
.then(function(idToken) {
// API call with Authorization: Bearer `idToken`
fetch(`https://api.url/${fetchPath}`, {accept: "application/json"})
.then(cb);
}).catch(function(error) {
// Handle error
});
}
but I got an error about an Invalid Hook Call.
Can anyone point me in the right direction?
Upvotes: 1
Views: 284
Reputation: 599041
The code you have to get the ID token looks fine to me.
How to pass it to the API depends on what that API expects, but since you mention ```Authorization: Bearer idToken
`` that would typically look like this:
fetch(`https://api.url/${fetchPath}`, {
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer ' + idToken
}
})
Upvotes: 1