Firebase Cloud Functions authentication for Android App - android

I'm building an Android App that searches for nearby locations. I use Firebase login system (Login with email and password, and login with Google, Facebook, etc), therefore I would also like to build an API with Firebase. (also because I need the app to be more complicated) I have built a serverless API with Firebase Cloud Functions and I can make GET/PUT requests with Postman. However, I would like to secure these endpoints, similar to how JWT secure a RESTAPI, so that only users who logged in the App can make requests. How do I achieve this? I have looked at "authorized-https-endpoint" but it seems like it only allow Google-Sign-In.
Or is there a way that I can still use Node and Mongodb RestAPI, and secure it using the accounts logged into Firebase?
Here is a piece of the backend code
app.get('/api/read/:item_id', (req, res) => {
(async () => {
try {
const document = db.collection('items').doc(req.params.item_id);
let item = await document.get();
let response = item.data();
return res.status(200).send(response);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
})();
});
exports.app = functions.https.onRequest(app);
Thank you guys so much in advance.

Use Firebase Callable Functions. They fulfill your requirement.
Refer: https://firebase.google.com/docs/functions/callable
In the case where there are issues with the function calls, please refer to this: firebase.google.com/docs/functions/callable-reference.
As mentioned here this is to be used only if the SDKs don't work for you

The authorized-https-endpoint example supports all forms of auth on the client, as long as it's going through the Firebase Auth SDK. In all cases, the client can send an auth token to the function, and the function code can use the Firebase Admin SDK to verify the token. It doesn't matter how the user authenticated - any Firebase user account will work.
You can also use a callable function, which will automatically perform the validation for you in the exact same way. Your code must then check to see if a user was authenticated using the calling context before continuing.

Related

Firebase custom auth with Gigya

My goal is to integrate Firebase Realtime Database within my Android app which already has an authentication layer (Gigya) that isn't managed by me.
The DB structure could be:
{
"users":
"gigya_id1": {
// user's objects
},
"gigya_id2": {
// user's objects
},
.....
}
I also want to add a little of security and rules to avoiding that a user can't READ/WRITE other users stuff.
I read about firebase custom auth but as I said, I don't have access to backend (and there is not doc about gigya custom token and firebase integration)
Does anyone have experienced with an integration like this one?
What you want to do can be achieved pretty easily.
You can pull the JWT from Gigya whenever a user authenticates by calling to
gigya.accounts.getJWT()
And pass the JWT in the response from Gigya to the custom auth method in Firebase, following this guidelines: https://firebase.google.com/docs/auth/web/custom-auth

react native android firebase sign in with apple [Error: The supplied auth credential is malformed, has expired or is not currently supported.]

I am implementing sign in with Apple. I can successfully see the Apple login page. I key in the correct credentials. It should be able to sign in/sign up to the firebase based on the returned value from Apple.
However I am getting this error Error: The supplied auth credential is malformed, has expired or is not currently supported. Something must be wrong at the firebase side? You may refer to the onPressAppleLogin function below on the logic. Many thanks!
What I have done:
In Firebase
Authentication with Sign-in provider Apple enabled
My service id is co.myexampleapp.signinwithapple
My authorization callback is https://my-example-app.firebaseapp.com/__/auth/handler
In developer.apple.com
I created a service id co.myexampleapp.signinwithapple with the service Sign In with Apple enabled
I added my-example-app.firebaseapp.com for the Domain and https://my-example-app.firebaseapp.com/__/auth/handler in the Return URLs
My React Native source code
import { appleAuthAndroid } from '#invertase/react-native-apple-authentication';
import firebase from 'react-native-firebase'
getRandomString = (length: any) => {
let randomChars =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
let result = ''
for (let i = 0; i < length; i++) {
result += randomChars.charAt(Math.floor(Math.random() * randomChars.length))
}
return result
}
onPressAppleLogin = async () => {
const rawNonce = this.getRandomString(20);
const state = this.getRandomString(20)
appleAuthAndroid.configure({
clientId: 'co.myexampleapp.signinwithapple',
redirectUri: 'https://my-example-app.firebaseapp.com/__/auth/handler',
responseType: appleAuthAndroid.ResponseType.ALL,
scope: appleAuthAndroid.Scope.ALL,
nonce: rawNonce,
state,
});
const response = await appleAuthAndroid.signIn();
const appleCredential = await firebase.auth.AppleAuthProvider.credential(response.id_token, rawNonce)
const appleUserCredential = await firebase.auth().signInWithCredential(appleCredential) // error happens here!
}
This is 100% due to the wrong Services ID on the server or the client.
I was working on a project in which we have Django as the backend server the backend developer used a different Services ID on the server & I on the client-side used a different Services ID.
How we solved this issue.
Open the Firebase console in the general settings check the bundle ID of the ios app compare it with the bundle ID in your Xcode. Make sure the Services is ID is correct and you have the latest provisioning profile with the Services Id added inside it.
Read this article to understand how to create a service ID. https://firebase.google.com/docs/auth/android/apple?authuser=4
You need to add the same services ID that you created above in the firebase console where you enable apple auth service in the authentication section
In your case you need to add service id
co.myexampleapp.signinwithapple
in the input box that is shown in the screenshot.
There is some sort of error in initializing the credentials.
Three types of errors may occur:
In the response, the token may be get expired. In that time you can use refresh token function to get new token.
Have a look at the rules in the firebase, if you initialized your app in the locked mode read and write will be set to false. If it so, change it to true.
Check whether you have enabled Api keys.
Important Check whether you enabled the third party access for the Apple Id.
Since the problem is with token, I suggest you to check the following.
Make sure you provided your email in support email in firebase project settings.
Try logging out before performing signing in operation. Due to improper logout during development this may happen.
Make sure you always logout before signin. Helped me in some cases.
Device time - since the token generated will be based on timestamp.

React native firebase cloud messaging token

I would like to add push notifications to my react native App but I would need some clarifications as there are plenty of different informations and implementations all over the web on that subject.
Currently my App is communicating with a node.js backend. So I have used the Firebase Web SDK in order to send push notifications to app clients.
Now it's time to register the app clients to Firebase Cloud Messaging in order to get tokens and save them with user related data. Then to be able to send targeted notifications to specific users (node.js backend role).
I've read to use the react native firebase library and more especially the messaging module to accomplish that.
Following that Device registration token tutorial, it's pretty clear. But where is the best place to request a token ? I assume that it should be when the user logs in to the App but we are not sure to get the token on time...
With that code we retrieve an existing token:
firebase.messaging().getToken()
.then(fcmToken => {
if (fcmToken) {
// user has a device token
} else {
// user doesn't have a device token yet
}
});
Tell me if I'm right:
I understand that if the app instance has already a token, I'll get it and it's time to associated it with user related data in database. But if it doesn't, I need to listen for a new token using that :
componentDidMount() {
this.onTokenRefreshListener =
firebase.messaging().onTokenRefresh(fcmToken => {
// Process your token as required
});
}
componentWillUnmount() {
this.onTokenRefreshListener();
}
But where should I start listening for it ? On the login component ? If the user log in before getting the token and navigate to another component, so the login component will be unmounted. It will be still listening ? And then I need to update the user data with the token ?
Or simply when the user log in, I need to wait till getting the token before navigate to another component ?

How to do a email verification to firebase user for signup and email update using FirebaseAuth? [duplicate]

Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.

How to implement server side sessions in node.js with express for an android app?

Hello all i am making an android app in whiich i have multiple account login at a time now my question is that i for multiple logins i should use sessions to verify every account user that is logged in. Now i am using express on the server side i have read a lot of documentation on storing sessions in node.js
Express-session (Though it is only good for development but not for production but not for my app)
Cookie-session
connect-Redis
connect-mongo
I have also heard about json web tokens where i can generate unique tokens and then i can pass the tokens to the client using res.json({user_id:"user1", token: "generated_token here"})
I have also heard about passport but dont know how it is going to do this also as in passport i use express-session by default will it be good for production or not ??
Now my first question is i have read all of there docs and nowhere it is mentioned where i am creating unique tokens for every user that is signing up.
Second question as i am using my server for android app there will be no use of cookie i will be sending user token as in parameter req.body.token now how to cmpare this with current user_id.
Actually i dont get the flow of control i mean how everything is going on in session in node.js. Also what is this secret is this thing generating unique tokens or what. Also i mean about 100000 of users are registered for my app now please tell me accordingly which way should i use for my app.
I have asked this question previously but there i did not mention that as i am not making a website how to do this(As in my case there will be no use of tokens)
I know this question i am asking is very vague but please bear with me i just want to understand how sessions are used in node.js
Thanks Anways
I'll try to answer this, but it is vague (as you pointed out). I'm going to make an assumption that your Android app is a native Android app and is going to be connecting to some sort of NodeJS backend in the cloud that is based on ExpressJS. If that's not the case, please clarify your thoughts in an update to your question.
The best idea for this specific scenario is to look to the cloud provide. Azure App Service Mobile Apps, for example, allows you to implement authentication - it eventually returns a JSON Web Token (http://jwt.io) to authenticate each request.
If you don't want to be beholden to a cloud provider, but want to run it yourself, you are going to have to implement the token generation and checking yourself. This generally follows the form:
Set up a WebAPI endpoint (maybe /signin) which takes whatever token the identity provider gives you, verifies the information and returns a JWT - there is an NPM module (jsonwebtoken) for producing the JWT. Ensure the JWT includes the identity of your user. I tend to use email address for the identity.
Your Android application will do a WebAPI request to your backend with an Authorization header, the value of which is "Bearer "
Your NodeJS API will use JWT authorization to validate the JWT and extract the user identity so you can use it in your API logic.
The important thing to note in this specific scenario is that your backend code is implementing a WebAPI - there are no cookies nor sessions in the API. The only thing that is linking the user from the client code to the backend code is the JWT.
As a short piece of code, here is how you verify a JWT:
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var jwtCheck = jwt({
secret: new Buffer('your-jwt-secret', 'base64'),
audience: 'your-jwt-audience'
});
app.get('/api/protected', jwtCheck, (req, res) => {
// Your code here
});
app.listen(process.env.PORT || 3000);

Categories

Resources