I have followed the link and have done the configuration on the server as mentioned.
"/users":
post:
description: "<Description>"
operationId: "<OperationID>"
produces:
- "application/json"
responses:
200:
description: "user List"
schema:
$ref: "#/definitions/echoMessage"
parameters:
- description: "Search Criteria"
in: body
name: message
required: true
schema:
$ref: "#/definitions/echoMessage"
security:
- firebase: []
and
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/<Project-ID>"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
And after going through JWT standards I came to know that while calling calling the service we have to add Authorization header with Bearer so I have added the header as follows,
Authorization: Bearer
I initially tried with
String token = FirebaseInstanceId.getInstance().getToken();
But it gave error so I tried with,
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) {
firebaseUser.getIdToken(true)
.addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult getTokenResult) {
String token = getTokenResult.getToken();
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.PREFS_FCM_TOKEN, token);
editor.apply();
}
});
}
But even with both codes I am getting error as 401 and invalid_token
After so many days of struggle I am able to solve the issue.
I solved the issue by following this,
"/users":
post:
description: "<Description>"
operationId: "<OperationID>"
produces:
- "application/json"
responses:
200:
description: "user List"
schema:
$ref: "#/definitions/echoMessage"
parameters:
- description: "Search Criteria"
in: body
name: message
required: true
schema:
$ref: "#/definitions/echoMessage"
security:
- firebase: []
and
firebase:
authorizationUrl: ""
flow: "implicit"
type: "oauth2"
x-google-issuer: "https://securetoken.google.com/<Project-ID>"
x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken#system.gserviceaccount.com"
x-google-audiences: "<Project-ID>" //I have added this, this was the main culprit.
as mentioned in the comment, I was missing
x-google-audiences: ""
in the server configuration.
And for another clarification for which token to use: We have to use the second approach that I have mentioned in the question, i.e, as below,
FirebaseUser firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (firebaseUser != null) {
firebaseUser.getIdToken(true)
.addOnSuccessListener(new OnSuccessListener<GetTokenResult>() {
#Override
public void onSuccess(GetTokenResult getTokenResult) {
String token = getTokenResult.getToken();
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString(Constants.PREFS_FCM_TOKEN, token);
editor.apply();
}
});
}
Related
After user signs in on my Android App with Firebase I want to send the Firebase Token as a String param via GraphQL Mutation.
Then receive it on my Express.js API inside the GraphQL mutation resolver and verify the token with the Firebase Admin SDK.
I have no idea if this is the correct way, all I want is to get the UID from the Token and check with Prisma if the UID is already existing on my MySQL User Table, if not then create a new user.
This should be done whenever the user inside the app uploads a new file, likes a post, comments etc.
I have absolutely no Idea if this is the way to do it.
Here is my Firebase Object (firebaseApp.js):
const admin = require('firebase-admin')
const serviceAccount = require("./.firebase/service-account.json");
const firebaseApp =
global.firebaseApp ??
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
})
// store on global object so we can reuse it if we attempt
// to initialize the app again
global.firebaseApp = firebaseApp
Here is my Mutation Resolver:
const db = require('../firebaseApp')
module.exports = {
Mutation: {
authenticateUser: async (parent, { token }) => {
db.auth().verifyIdToken(token)
.then((decodedToken) => {
const uid = decodedToken.uid;
return {
message: "User is authenticated: " + uid
}
})
.catch((error) => {
return {
message: "User is not authenticated: "
}
});
}
}
}
Here is the output when I try to send a token with the mutation:
db.auth is not a function
I have the strong feeling that I have a big misconception in my head and that this is aboslutely not the way to do it, I literally cannot find anything on the internet which explains this using my tech stack (Apollo GraphQL, Node.js, Prisma)
Would appreciate some help
With the recent release of FirebaseInstanceId and FirebaseCloudMessaging (21.0.0) Firebase has deprecated iid package and both getToken() and getId() methods are now deprecated.
According to the Firebase release note the method getToken() is moved to FirebaseMessaging
Before:
FirebaseInstanceId.getInstance().getToken()
After:
FirebaseMessaging.getInstance().getToken()
Which gives use the fcmToken, but to retrieve instance id, there's no method available in FirebaseMessaging nor FirebaseInstanceId.
So, Is instance_id considered a useless id and should no longer be used? or is there a replacement for this?
FirebaseInstanceId class is deprecated, to get token use FirebaseMessagingClass. The token can be generated using the following code:
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "Fetching FCM registration token failed", task.getException());
return;
}
// Get new FCM registration token
String token = task.getResult();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
Regarding the Firebase InstanceId, this is what the official document says:
public Task getInstanceId () ->
This method is deprecated.
For an instance identifier, use FirebaseInstallations.getId() instead. For an FCM registration token, use FirebaseMessaging.getToken() instead.
Fcm Token
Before deprecation
val fcmToken = FirebaseInstanceId.getInstance().getToken()
Replacement
val fcmToken = FirebaseMessaging.getInstance().getToken()
FirebaseInstanceId#getId
Before deprecation
val istanceId = FirebaseInstanceId.getInstance().getId()
Replacement
Checking out the code of FirebaseInstanceId#getId() I saw the suggestion that you should use FirebaseInstallations#getId instead.
This method is deprecated
Use FirebaseInstallations.getId() instead.
val instanceId = FirebaseInstallation.getInstance().getId()
FCM Token:
Use firebase_messaging package
String? token = await FirebaseMessaging.instance.getToken();
Installation ID:
Use flutterfire_installations package
String id = await FirebaseInstallations.instance.getId();
Installation auth token:
String token = await FirebaseInstallations.instance.getToken();
try this one
public String getToken() {
String token;
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
if (task.isSuccessful()) {
token = task.getResult();
}
}
});
return token;
}
So, In my flutter app, I am trying to add functionality to change email.
I used userData.updateEmail(email) method, but it gives this error:
Unhandled Exception: PlatformException(ERROR_REQUIRES_RECENT_LOGIN, This operation is sensitive and requires recent authentication. Log in again before retrying this request., null)
On surfing for a solution on the Internet I got to know, I need to reauthenticate user by this method:
userData.reauthenticateWithCredential(credential)
But I can't find a way to get credential to pass to reauthenticateWithCredential method.
Some code snippets (tho I feel they are unnecessary):
initUserData() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
setState(() {
userData = user;
});
}
updateEmail(String value) async {
// value is the email user inputs in a textfield and is validated
userData.updateEmail(value);
}
Note: I am using both login with google and password-email login.
There is a re-authenticate method. You just need to obtain the user's password for calling the method.
FirebaseUser user = await FirebaseAuth.instance.currentUser();
AuthResult authResult = await user.reauthenticateWithCredential(
EmailAuthProvider.getCredential(
email: user.email,
password: password,
),
);
// Then use the newly re-authenticated user
authResult.user
I had this problem too and I found the solution. You can get the AuthCredential for the providers you're using like this:
EmailAuthProvider.getCredential(email: 'email', password: 'password');
and
GoogleAuthProvider.getCredential(idToken: '', accessToken: '')
Both methods return what you're looking for.
It is working for me
Future resetEmail(String newEmail) async {
var message;
FirebaseUser firebaseUser = await _firebaseAuth.currentUser();
firebaseUser
.updateEmail(newEmail)
.then(
(value) => message = 'Success',
)
.catchError((onError) => message = 'error');
return message;
}
When you want to change sensitive informations on Firebase you need to re-authenticate first to your account using your current credentials then you can update it.
Currently flutter has no reAuthenticate method for Firebase so you need to call signInWithEmailAndPassword or any other signIn method.
Performing the get() function in security rules is not working.
It returns permission denied on the client, but passes in simulation.
The config/permissions layout is an array structure:
config/permissions-->
---------------------------> CollectionName1 :
----------------------------------------------------> 0 : UID1
----------------------------------------------------> 1 : UID2
---------------------------> CollectionName2 :
----------------------------------------------------> 0 : UID3
----------------------------------------------------> 1 : UID4
I also tried to use single key/value fields in the config/permissions as so
config/permissions-->
---------------------------> CollectionName1 : UID1
---------------------------> CollectionName2 : UID3
with the rule
allow read: if request.auth.uid == get(/config/permissions).data[c] and this passed simulation and failed on the app. If I hardcode the UID instead of request.auth.uid it gives the same result.
UID is definitely correct on the app. This was tested by using the following rule, where it passed in simulation AND the app.
allow read: if request.auth.uid == 'USER_ID_HERE'
and by comparing the logcat output of the UID to the one above.
Please help. This is the Nth day of trying to find a suitable way to structure and query Firestore. I'm certain this is an issue with either the get() call or the way I am writing the call.
Android Code:
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.setTimestampsInSnapshotsEnabled(true)
.build();
db.setFirestoreSettings(settings);
Log.d("UID", FirebaseAuth.getInstance().getCurrentUser().getUid());
DocumentReference docRef = db.collection(collection).document("X153#111");
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Log.d("FIREBASE", "DocumentSnapshot data: " + document.getData());
} else {
Log.d("FIREBASE", "No such document");
}
} else {
Log.d("FIREBASE", "get failed with ", task.getException());
}
}
});
I am creating an app that allows users to register themselves.
Using react-native and firebase works, the are registered and are logged in. Even the additional data is stored in the realtime database (I checked it).
But I am getting a message saying "creating user failed" (it is one of the messages I have setup).
This is the code I use to create users and add additional data to the realtime database:
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((user) => {
firebase.database().ref('users/' + user.uid).set({
firstName: firstName,
lastName: lastName,
email: email,
code: code
})
})
.then(user => loginUserSuccess(dispatch, user))
.catch((error) => {
createUserFail(dispatch)
console.log(error);
});
I also checked the debugger in android studio (don't know about ios yet) and saw the following comment:
TypeError: undefined is not an object (evaluating 'user.uid')
Still everything is saved, but the error message was shown. What am I doing wrong?
I know this is a year old but I ran into the same issue and here's a more direct solution for anyone running into the same issue. When you create a user the user object is a part of the Firebase response not the response itself. So just prepend "res" to your original code like this:
firebase.auth().createUserWithEmailAndPassword(email, password)
.then((res) => {
firebase.database().ref('users/' + res.user.uid).set({
firstName: firstName,
lastName: lastName,
email: email,
code: code
})
})
Ok, finally I got it working. What I did was, after the first then, checking for the currentuser (because the user will be loggedin automatically), then getting the uid and using that:
if (firebase.auth().currentUser) {
userId = firebase.auth().currentUser.uid;
if (userId) {
firebase.database().ref('users/' + userId).set({
firstName: firstName,
lastName: lastName,
email: email,
code: code
})
}
}
This works.
firebase.auth().createUserWithEmailAndPassword(email, password).then((user)=>{
if (firebase.auth().currentUser) {
userId = firebase.auth().currentUser.uid;
if (userId) {
firebase.database().ref('users/' + userId).set({
firstname:firstname,
lastname:lastname,
email:email,
password:password,
town:town,
addInterest:addInterest,
photoUrl:false,
emailVerified:false,
uid:userId,
status:true,
online:true
})
}
}
}).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log('Register!');
console.log(error);
})
Full Code so easy to use. 100% work!
You didn't say if you were using this in the context of an action creator but if you did, here is another possible solution. Let's make it more interesting, its an app for adding new employees:
export const employeeCreate = ({ name, phone, shift }) => {
const { currentUser } = firebase.auth();
return () => {
firebase
.database()
.ref(`/users/${currentUser.uid}/employees`)
// add a .then() to ensure after employee is created
// we want to navigate them back to employee list screen
.push({ name, phone, shift })
.then(() => Actions.pop());
};
};
The Actions would be imported from react-native-router-flux like so:
import firebase from 'firebase';
import { Actions } from 'react-native-router-flux';