Android app request Firebase custom authentication - java

I'm new to Firebase and Android programming, I have some questions regarding Firebase custom authentication.
I build an android application of social report (for broken public infrastructure) which needed simplest solution for automatic authentication. Since it is a social report app in which users shouldn't be bothered in registration process by inputing any kind of data. So I decided to use Android uuid as an identifier of user instead of email/user name/etc. I loosely implement user authentication and registration. It only need Android device uuid to register/authenticate (don't even need a password). Although, I think I've secured user data in firebase security rules well enough.
I've successfully created a custom automatic authentication/registration server with Go language which mints and store the data from the Firebase itself. These are my current workflow:
The Android client automatically sends a request to my auth server. The request data contains Android uuid and several other data. I'm going to put it in onCreate activity. So every time user opens the application up, it will request for a token.
My auth server checks whether that particular uuid is stored in my Firebase. If it is, then generate a JWT. If not, my server will automatically create a new user data entry in my Firebase and send back a new JWT.
Someway save the JWT within the client app, and use that to do data transaction with firebase.
I managed to learn the Firebase library for Android, it is great and very simple. I found a lot of Android http request libraries (two of them are retrofit and volley). Yet, I still uncertain of the best way to send the auth request from the Android client.
What is the preferred/simplest way to send custom auth request in the client app, based on the requirements and workflow I've specified above? Do I need to use http request library to simplify the code? sample/snippet of code would be very helpful. What is the best way to store and use the JWT in the client app? Is my current workflow good enough? Evaluations are much appreciated.
As a side note, this is my school final project, not a production application. So I don't mind elaborate cases like whether user is having more than one phone, or buying second phone which ought to have same uuid with the previous owner, etc. Also, please spare my weird grammar/non-idiomatic language as I'm not a native english speaker.

The easiest way with Android is to use signInWithCustomToken() on a Firebase auth object (FirebaseAuth).
Here is the reference in the docs, including sample implementation code:
https://firebase.google.com/docs/auth/android/custom-auth
Good luck with the project.

Related

AWS Cognito Sign-In with Java SDK for desktop application

I searched a lot, but it seems impossible to find a solution from start to finish to this topic. As a premise, I've already implemented Cognito sign-up, sign-in and refresh of credentials in two native apps for both iOS and Android, so I have developed a (at least) basic understanding of the authentication flow.
These mobile apps use the simplest cognito setup possible: a user pool, an identity pool with a IAM role for authenticated users and no unauthenticated usage possible. I'm not using (at least for now) Facebook, Google or Amazon login, nor other authentication methods.
Now I need to make a desktop version of those apps in Java, and it seems to me a completely different beast. What I would like to do is this:
Open the login window in my Java desktop application;
Insert username and password in their fields and press a login button;
Getting some credentials and start using the application connecting to other AWS services, specifically I need to use S3, Lambda and DynamoDB.
The way to achieve this is on paper reasonably simple:
Get a token from a Cognito user pool;
Give this token to a Cognito identity pool in exchange for some credentials;
Use this credentials to access other AWS services.
After reading a lot of documentation, downloading a lot of different projects examples and a lot of despair, I've eventually found the way to implement this in the mobile apps. For example, in Android the authentication flow works like this:
Instantiate a CognitoUserPool, using a UserPoolID, an AppClientID, a PoolRegion and (optionally) a ClientSecret;
Instantiate a credential provider, using an IdentityPoolID and a PoolRegion;
In the app UI, insert a username and password, and press the Login button;
Retrieve a CognitoUser using that username from the UserPool instantiated earlier;
Get a CognitoUserSession for that CognitoUser, using an AuthenticationHandler with various callbacks to pass the password when needed;
Add that CognitoUserSession to the credentials provider instantiated earlier, in form of a TokenKey + the JWT token extracted from the session.
At this point, whenever I need to access S3, Lambda or DynamoDB, I simply pass this credentials provider as a parameter for their clients constructors.
To implement the same functionality with the Java SDK seems to me much more difficult.
I managed to implement users Sign-Up fairly easily. However with users Sign-In I don't know where to start at all.
Every example does this in a different way. On top of that, every example uses particular use cases such as developer authenticated Sign-Ins, or custom urls to connect to some owned backend. Why is so difficult to find an example for a basic use case like the one I need? I'm starting to think my basic use case is not basic at all, but rather atypical. Why would login with a username and a password against the default users/credentials service for AWS be atypical, however, I don't really know.
The best I've done so far is copying the relevant classes from this example project (from which I've also taken the Sign-Up part, that works pretty well) and getting to print the IdToken, AccessToken and RefreshToken in the console. They are printed correctly and are not null.
What I cant't really understand is how to get the credentials and add them to a credentials provider in order to instantiate the clients to access other AWS services. The only way I see in the project to do that is to call the method
Credentials getCredentials(String accessCode)
which I suppose it should accept the access code retrieved with the InitAuth method (that starts an OAuth2.0 authentication flow, please correct me if I am wrong). The problem is that I can't find a way to retrieve that code. I can't find an online example of an access code to see how it looks. I tried to put one of the tokens and the web request responds
{"error":"invalid_grant"}
which suggests its not a valid code, but at least the web request is valid.
To make it more clear, what I can do is this:
String username; //retrieved from UI
String password; //retrieved from UI
//I copied AuthenticationHelper as is from the project
AuthenticationHelper helper = new AuthenticationHelper(POOL_ID, CLIENT_APP_ID, CLIENT_SECRET);
//I then retrieve the tokens with SRP authentication
AuthenticationResultType result = helper.performSRPAuthentication(username, password);
//Now I can successfully print the tokens, for example:
System.out.println(result.getAccessToken());
How can I retrieve the credentials from here? Where I should put the identity pool id? In Android I simply add the JWT token to an HashMap and use it like
credentialsProvider.setLogins(loginsMap).
Furthermore, this project contain classes with hundreds of lines of code, BigInteger variables, hardcoded strings of many lines of random characters (some sort of key or token I suppose) and other black magic like that (especially in the AuthenticationHelper class). Another thing I don't like about this solution is that it retrieves credentials through manually written web requests (with another separated class created ad hoc to make the request). Really isn't there in the Java SDK some handy method that wraps all those things in a bunch of elegant lines of code? Why call it an SDK than? The iOS and Android SDKs handle all that on their own in such a simpler way. Is this due to the fact that they expect a developer of desktop app to be way more able/expert, in contrast to the average guy that some day, getting up from bed, decides to make an iOS/Android app [alludes to himself]? This would explain their effort to make the mobile SDKs so developer-friendly in comparison.
Onestly I find really hard to believe that I have to do that, reading who knows what on a doc page who knows where, to Sign-In a user, which makes me think that I'm really missing something. I literally read every stack exchange question and documentation I was able to find. The fact is that there is almost always an AWS documentation page for what I need, but to actually find it is not so simple sometimes, at least for Cognito documentation.
I read that I can put a file with the needed credentials in the PC filesystem and the Java SDK will use those credentials to access all the resources, however from my understanding this method is reserved to Java applications running on a server as a backend (servlets), where the end user can't access them through his browser. My application is a desktop app for end-users, so I can't even consider to leave AWS credentials on the user PC (please correct me if I'm wrong, I would really love to make something so simple).
What really scares me is that Sign-In with a user pool and identity pool might not be possible at all. I know that Cognito related stuff was added to the Java SDK much later it was available for iOS, Android and JavaScript. But if they added it, I suppose It should support an authentication flow at least similar to those of the mobile counterparts.
What worsen the problem even more is that I initially made all the functionalities of my application to work offline. I thought that I would have eventually integrated AWS in the app. In this way the application is a bit more modular, and the AWS related stuff in concentrated in a package, detatched from the rest of the application logic and UI. In my sea of ignorance this seems a good practice to me, but now, if I cannot manage to resolve this problem, I've thrown months of work in the trash, only to realize that I have to build a web app beacuse JavaScript is much more supported.
Even on MobileHub the only options to create a ClientApp on Cognito is for iOS, Android, JavaScript and React-something.
When documentation or examples are provided for other languages/SDKs, Java is often omitted and the most frequent I see among the options is .NET.
To make my frustration even bigger, everytime I search something on a search engine, the fact that the word "Java" is contained in the word "JavaScript" obfuscates the few results that could be useful, because all the JavaScript SDK related stuff is generally higher ranked in the search engines than Java's (this could explain in part why .NET related stuff seems more easy to find, at least on StackOverflow or others Q&A sites).
To conclude, all of this created some questions in my head:
Why so few people seem to need this authentication method (with username and password)? It seems to me a pretty common and reasonable use case for a desktop application. I know that web apps growth is through the roof, but given that Java is one of the most used languages today, how is it possible that nobody needs to do a simple login from a desktop application? Which leads to the next question:
Is there something inherently bad/wrong/risky/stupid in using the Java SDK for a desktop application? Is it intended only for usage on a server as backend or for a web app? What should be the solution than, to make a desktop application that connects to AWS services? It is wrong to do an AWS connected desktop app at all? Should a web app the only option to consider? Why? I opted for Java to implement an application that would run on Widows, macOS and Linux. I also chose Java because i thought it would be mostly similar to the Android SDK in its usage, given its code should be indipendent from the platform UI, making simple to reuse code. I was wrong.
If there's nothing wrong in using the Java SDK like this, could some
good soul please help me find an example that goes from putting a
username and a password in two fields, and instantiate a client to
access other AWS services (such as an S3 client) in a Java desktop
application?
Tell me everything you need to know and I'll edit the question.
Please someone help me, I'm loosing my mind.
Probably too late for the OP but here is the process I used to get credentials from Cognito after obtaining the JWT identity token. Once the JWT is obtained through SRP Authentication I got the Identity Id using the Federated Pool Id and passing a login map of the Cognito Idp Url and the JWT. The url is completed with your aws region and your Cognito User Pool Id.
//create a Cognito provider with anonymous creds
AnonymousAWSCredentials awsCreds = new AnonymousAWSCredentials();
AmazonCognitoIdentity provider = AmazonCognitoIdentityClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(REGION)
.build();
//get the identity id using the login map
String idpUrl = String.format("cognito-idp.%s.amazonaws.com/%s", REGION, cognitoUserPoolId);
GetIdRequest idrequest = new GetIdRequest();
idrequest.setIdentityPoolId(FED_POOL_ID);
idrequest.addLoginsEntry(idpUrl, jwt);
//use the provider to make the id request
GetIdResult idResult = provider.getId(idrequest);
return idResult.getIdentityId();
If you're using a different login provider then that url needs to change, but this should get the Identity Id. Next its a similar request to get the IAM credentials by passing the Identity Id and that same login map.
//create a Cognito provider with anonymous creds
AnonymousAWSCredentials awsCreds = new AnonymousAWSCredentials();
AmazonCognitoIdentity provider = AmazonCognitoIdentityClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCreds))
.withRegion(REGION)
.build();
//request authenticated credentials using the identity id and login map for authentication
String idpUrl = String.format("cognito-idp.%s.amazonaws.com/%s", REGION, cognitoUserPoolId);
GetCredentialsForIdentityRequest request = new GetCredentialsForIdentityRequest();
request.setIdentityId(identityId);
request.addLoginsEntry(idpUrl, jwt);
//use Cognito provider to perform credentials request
GetCredentialsForIdentityResult result = provider.getCredentialsForIdentity(request);
return result.getCredentials();
This took me a full week to figure out. AWS Java documentation is pretty terrible in my opinion. Hopefully this helps someone out.

Rolling a user authentication system for Android app

I'm a bit confused on how I can implement a user system into my application.
For a small overview, the mobile application needs to allow users to login or register, follow other users, and favorite/like items.
I've checkout out the documentation on Google Cloud Platform for implementing User Auth:
https://developers.google.com/identity/protocols/OpenIDConnect
https://cloud.google.com/appengine/docs/standard/java/users/
https://cloud.google.com/appengine/docs/standard/java/oauth/
I've used Parse in the past, and would expect the Firebase User Auth system to offer a similar experience, however due to Firebase conflicts with App Engine, that route is a no-go.
I understand there is also the User API, which can be used for things like restricting Cloud Endpoints calls to logged in users.
How can I roll a user auth system for my application? The best solution that comes to mind would be to just store user emails and passwords in Google Cloud Datastore, and check if the combination exists when a user logs in. However, I'm fairly unfamiliar with creating user systems and this seems like it would come with some sort of security issues.
you can use Firebase Authentication with Google App Engine. Your information that you have to use manual scaling instance is not correct. This was a bug and were fixed. Please see the following post for more informations
Verify Firebase Token at Google App Engine

How to connect android users to my database / web application?

I have wrote a simple web application with few tables. It has it's administration area where you can manage it's table. Basic CRUD operations.
However, I need to develop an Android application which will retrieve information from this web application trough API. So I am going to write a simple API methods for fetching data. Also there will be sometimes when Android user will save some of its data to database.
Android application needs to be able to list items stored in database and bookmark some of those items over HTTP.
To me problem is how to implement SingIn / SignOut operations using Android's Google account. For example, application GMail is always signed in (at least on my device) and I want my application to be always signed in.
Then, how can I manage what items user bookmarked? Should I create a table android_bookmarked_items (android_user_id, item_id)? But then what should be android_user_id? Do I need to use OAuth?
I am doing this kind off sign in for the first time and I am really confused how to connect this web application with android user and manage bookmarked items per user...
You can make use of Android AccountManager. Check out How to get the Android device's primary e-mail address
I think i have found solution by using Google Sign-In for Android. I get idToken for currently login user before each POST request and verify it on server side. Also from the token I get property sub which is user id and store this in my database...
Auth with a backend server
However, I am pretty new to this stuff, tokens and authentication using google, I would like for someone more experinced to confirm that my solution is fine and secure...

How to add the data to Google Analytis by using java (programmatically)

At the current moment, I am trying to understand how to add any data to GA. I read the data from my GA account using Core Reporting API and Managment API without any problems. But now I want to add the data (the number of phone calls) to GA account programmatically. Somebody can explain me step by step - how can I do this?
The Measurement Protocol is how we send data to Google Analytics. The JavaScript snippet that we use in our websites also uses the Measurement protocol as do the SDK's for Android and IOS. Unfortunately there is no (official) SDKs for the other languages like Java for instance.
That being said you can technically code it yourself in any language that can handle a HTTP get or a HTTP post. I have personally done it for C#.
POST /collect HTTP/1.1
Host: www.google-analytics.com
payload_data
The following parameters are required for each payload:
v=1 // Version.
&tid=UA-XXXXX-Y // Tracking ID / Property ID.
&cid=555 // Anonymous Client ID.
&t= // Hit Type.
A few tips to get you started.
Check out validating hits this is very useful in the beginning for debugging your requests.
some of the parameters are only valid for certain hit types. Make sure you check the documentation.
Cid is just a string it can be anything most people send a Guid its basically used by the server to identify a unique session.
if you are doing this for an application google analytics account remember to send screenview not pageview the same goes for web application.
check the realtime report on google analytics to see if your hits are getting recorded.
Update for question in comment:
I recommend while you are getting the idea of this you start with just using HTTP GET in a web browser. Its easer to test your requests against debug that way. For example put this in a browser.
https://google-analytics.com/debug/collect?v=1&tid=UA-123456-1&cid=5555&t=pageview&dp=%2FpageA
DP is document path and I am not sure why it is requiring that you send that.
ScreenView hit type VS PageView hit type.
There are two types of Google Analytics accounts ones for applications like android applications or sometimes web applications, and web sites. Application Google analytics accounts are meant to be used with ScreenView hit (the user checks a screen in the application) type and web accounts use PageViews (the user views a webpage). If you send a Pageview to an application Google Analytics account it will accept the hit but there will be no way for you to see the data. If you send a ScreenView to a web Google Analytics account it will again accept the data but you wont see it.

How to determine which user is making Rest requests from android application?

I am trying to build a Spray REST Web server for my mobile application on android (Eventually Iphones too). Currently, I am wondering how to determine from the server side which user is making REST Method requests. After some research I am understanding that android's SharedPreferences or an OAuth protocol can be utilized to handle user authentication. Still I am unsure how to create the entire picture of "This user is requesting some information". The message responses will be in JSON text, should the request's be in JSON as well?
I greatly appreciate all of your help, eagerly awaiting responses.
Currently, I am wondering how to determine from the server side which user is making REST Method requests.
The most adequate way to do this is to add auth layer to your server. There are many ways of how exactly you can do this, depending on security concerns you have to deal with.
Here is the list of auth schemes I would be looking into first of all:
Http basic auth (most simple one, stick with it if you can)
OpenID or OAuth (harder to implement, solves some problems that are out of scope of simply authenticating user. Note: OAuth is about authorization but can also be used to do authentication)
home-gown auth (may be implemented on different network layers, lots of options here. Do not recommend going here unless you really need to).
You can send more info from client side when user send request, you include unique info (Android ID, Ads ID for example)
server.address/request?command=abc&uid=UID...
. Another way is read IP address of the user and manage it by session.

Categories

Resources