Android authentication against Spring Boot API not working - android

I have a Spring Boot back end API using Auth0 JWT authentication and currently have two clients for it, a Vue SPA and an Android app. The Vue SPA works fine. It uses an SPA Application type in Auth0, and the authentication mechanism uses an Audience, like so:
{
"domain": "mycompany.auth0.com",
"clientId": "mySPAclientID",
"audience": "https://myaudience.mycompany.com"
}
I figured I'd be able to do something similar in Android, so I created a Native Application type in my Auth0 Dashboard, downloaded the corresponding quickstart, and attempted to authenticate. I am, of course, able to authenticate against Auth0 and get a JWT back, but the JWT does not work against my Spring Boot API, which is designated by my https://myaudience.mycompany.com audience and which my Spring Boot security config expects to be present in the JWT. My first thought was that I could simply add the audience to the login action in the Android app:
WebAuthProvider.login(auth0)
.withScheme("demo")
.withAudience(String.format("https://%s/userinfo", getString(R.string.com_auth0_domain)))
.withAudience("https://myaudience.mycompany.com") // added this
.start(this, new AuthCallback() { ... }
But this doesn't work. When I parse the returned JWT, the audience portion does not contain the expected block. It should look like this:
"aud": [
"https://myaudience.mycompany.com",
"https://mycompany.auth0.com/userinfo"
]
But instead it looks like this:
"aud": "myNativeClientID"
It's also missing the scope element entirely. What's the correct way to make this work? Do I need a new Auth0 API, which would require a new Spring Boot security mechanism? Or is there something simple I'm missing in the login request? Or some config I'm missing in my Auth0 Native Application? I've been through all the relevant documentation and nothing works. I'm not sure how to proceed, any help would be hugely appreciated.

With a helpful nudge by an Auth0 employee, I realized that I'd confused the Auth0 ID token with the access token. In Auth0, ID tokens are always issued as JWTs, but they can't be used to access Auth0 APIs, only access tokens can do that. The trouble is that unless you specify an "audience" in your login request, the access token is of a simple token format like this:
1v-QyDrPaJ5rOUBOk3g_0HtEwtN4C-4U
But when you add an audience (ie an Auth0 API, which is in turn referenced in your back end, whatever it may be, in my case Spring Boot), the access token becomes a JWT with all the requisite audiences and scopes (by default the scope is limited to openapi, I believe).
So because the access token was not a JWT (since I hadn't yet added the audience when I first examined the login response), I dismissed it, and was using the ID token, which as I mentioned can't be used to gain access to an Auth0 API. Once I reverted back to using the access token JWT, everything worked as expected.
Accepting this as an answer in case it helps anyone in the future.

Related

Mobile App webframe Authentication with Rails Devise

I am currently working on implementing a mobile app for our site that uses Ruby on Rails and Devise. The idea here is, at first, create a mobile login form that on successful login opens a web frame that is authenticated and allows the normal use of the (mobile optimised) site. Theoretically that should be possible.
I am having trouble with the following issues:
How do you get the pure session key for the user session via a json request? What methods can be used to manually generate it from devise, something that the sign_in(:user, user) method does?
Is it even possible to take that key and put it into the browser cookie the way it normally happens in devise, but on the mobile side?
I know that this is not the standard method of making mobile applications for the site, but I believe it should be possible.
You might want to consider using Devise Token Auth and treating your mobile application like just another webapp that requests permission from your main site. DTA is particularly nice since it takes care of managing the session tokens (renewing/expiring) and passing them onto the app requiring access. The issue is overriding your session controllers so that it automatically logs in after you already log in on the mobile app (or just rewriting your log in so it occurs in conjunction with the Rails site, rather than before). Considering you're already using Devise, this may also be more refactoring than you'd like.
If you want to put your authentication form on the mobile UI and pass the credentials over to the web frame, you need a way to pass data from the mobile app to the web frame.
How you accomplish this depends on what platform you're building on. I'm not really a mobile developer so I don't know for certain how difficult / easy these options are:
When opening the web frame, instantiate it with session data
Find a way to call methods on the client from the web frame. Something like getSessionData.
You could generate a fingerprint for the web frame, have the mobile UI send this data to the server, and then have the web frame authenticate with the server by sending the fingerprint.
Again, I'm not entirely sure how possible all these options are.
You should use token authorization and Android deep linking. It will allow you to login in the web browser and send a token to your app via deep linking.
OK, so I decided to make a webframe solution as follows, basically you post the login and password to a certain sign_in method specially designed to generate one-time sign in tokens for the application. You need two methods in the system to do that:
routes.rb
devise_scope :user do
get "sign_in_with_token/:token" => "sessions#sign_in_with_token"
post "get_login_token" => "sessions#get_login_token"
end
sessions_controller.rb (don't forget to add the method that increases the failed_sign_in_count on wrong password, otherwise that can allow brute force attacks)
def get_login_token
user = User.find_by_email(sign_in_params["login"])
password = sign_in_params["password"]
if user and user.valid_password?(password)
token = SecureRandom.hex(16)
user.update_attribute(:authentication_token, token)
render json: {token: token}, status: 200
else
render json: {error: "error"}, status: 403
end
end
and the method to sign in with that token
def sign_in_with_token
#user = User.where(authentication_token: params[:token], email: Base64.decode64(params[:email])).first
if #user
#user.update_attribute(:authentication_token, nil)
sign_in(#user, bypass: true)
end
redirect_to '/' # or user_root_url
end
That way the mobile app will work like this:
use the generic web frame to send ajax requests to the server and get that token for the user email if password is correct.
make a /sign_in_with_token/#{token from ajax}?email=#{base46 encoded email} link inside the app.
open that link inside the web frame and use the app as though you were logged in normally. Now the app can save email and password locally and use that logic to get the token again for another session. Later logging in will also be able to set the app id so that push notifications can be sent.
Appreciate any feedback or criticism on this solution.

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);

Protecting my Google App Engine API Endpoints

I have been doing a lot of research recently on securing my app engine. Currently, I've been reading through the question below and the links in that question:
How do I restrict Google App Engine Endpoints API access to only my Android applications?
However, it doesn't answer my problem. My question is similar to the question above, restricting access to my endpoint API to only my app. The guy seemed to have got it working when he inputs a correct email into the credentials.
My question is if I can achieve the same results without having to input any credentials. I want it so that only my app can use my endpoint API so to prevent other apps from abusing it and using up my quota. I already got a client id for my android application, and have placed it within my #API annotation. To test if it worked, I made a random value for the client id in the #API notation of another api class. However, my app was still able to use methods from both class. Any help?
-Edit-
From reading from the docs and researching further, the endpoint way of authorizing apps is by authenticating the user and for my API to check if user is null. My question is that in the process of authenticating the user, is Google somehow able to read my app's SHA1 fingerprint and authorize it to its list of client ids? If so, how can I replicate this process in my endpoint so that I check the SHA1 fingerprint of the app making the request and compare it to a set value? I don't understand the mechanics behind the endpoints very well, so correct me if I am understanding this wrong.
If the android app has access, then the user has access. A motivated party has many options for inspecting your protocol, including putting the device behind transparent proxy or simply running the app through a debugger. I do suggest running your app through ProGuard before publishing, as this will make the process [a bit] more difficult.
Ultimately, you'll need to make your appengine API robust against untrusted parties. This is simply the state of the web.
How you can protect your endpoint API is described here: http://android-developers.blogspot.com/2013/01/verifying-back-end-calls-from-android.html
The secret is that you request a token from Google Play using the following scope: audience:server:client_id:9414861317621.apps.googleusercontent.com where 9414861317621.apps.googleusercontent.com is your ClientId.
Google Play will look up the id at your endpoints app and return a Google-signed JSON Web Token if it finds the id. Then you pass that id in with your request. Above article says you should pass it in with the body. I would possibly rather add another parameter for that because otherwise you can't pass your own entities anymore. Anyway, your server backend receives the token, and you ask Google as described if it is authentic, before you process the API request.
If you pass in the token using an extra parameter, you can catch it on the server side by adding HttpServletRequest to your endpoint signature and then using request.getHeader("Yourname") to read it out. Make sure you never add the parameter as a URL parameter as it may be logged somewhere.
public void endpointmethod(
// ... your own parameters here
final HttpServletRequest request
) throws ServiceException, OAuthRequestException {
request.getHeader("YourHeaderName") // read your header here, authenticate it with Google and raise OAuthRequestException if it can't be validated
On the Android side you can pass in your token when you build the endpoint api, like this, so you don't have to do it with each and every request:
Yourapiname.Builder builder = new Yourapiname.Builder(AndroidHttp.newCompatibleTransport(), getJsonFactory(), new HttpRequestInitializer() {
public void initialize(HttpRequest httpRequest) {
httpRequest.setHeader(...);
}})
Hope this helps you make your endpoints API secure. It should.

Google+ login redirect_uri_mismatch error

I'm trying to implement one-time code sign in flow in my system.
Application contains of two parts:
1)Android application which requests Google+ for one-time authorization code
2)Rails server that receives one-time code from android application in request header and tries to exchange code for access_token and id_token from Google+
The problem is that everything works well if I get one-time code using JavaScript sign-in button in browser, but doesn't work when one-time code is obtained by Android application and then sent to my server.
I'm getting always
"error" : "redirect_uri_mismatch"
My server settings are following:
{ "web":
{ "client_id": "MY_REGISTERED_WEB_APP_CLIENT_ID",
"client_secret": "MY_CLIENT_SECRET",
"redirect_uris": ["postmessage"],
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token"
}
}
Now, how I'm requesting one-time code from Android app:
I use the same MY_REGISTERED_WEB_APP_CLIENT_ID as on my server for requesting one-time code. I don't know, maybe I have to use on Android another client id, that corresponds to my Android application? But all found documentation and articles are pointing to registered
Web app client_id.
Or maybe my rails server should be configured not for web, but for installed type of registered in Google Console apps?
Now regarding redirect_uris.
I've tried to set several redirect_uris in Google Console:
empty field
http://localhost:5000
https://localhost:5000
http://my.deployment.url/auth2callback
Web origins in Google console are set to
- http://my.deployment.url
- http://localhost:5000
Can't figure out what I'm doing wrong.
Actually I don't understand why I need to set this redirect_uris values, since I don't want to have callbacks from Google, I just want to get access_token and use it for accessing Google+.
This is happening because the redirect_uri your android app is using to create the initial login flow is different from the redirect_uri the server is using when it tries to excange the code for an access_token. The redirect_uri the user returns to and the redirect_uri used in the token exchange must match.
The proper redirect_uri in this case is "urn:ietf:wg:oauth:2.0:oob"

What is the proper way to validate google granted OAuth tokens in a node.js server?

I'm trying to authenticate a mobile application for the Android platform to a custom node.js server api. I would like to use Google OAuth2 tokens for this rather than roll my own authentication, since Android devices with Google Play installed make this available to app developers. I'm using the GoogleAuthUtil.getToken call from the Google Play Services library, documented here. I'm trying to follow the advice outlinedin this android developers blogpost
The getToken method is returning in my case a long 857 byte string. If I try to pass this token to Google's TokenInfo endpoint, it returns:
{'error': 'invalid_token', 'error_description': 'Invalid Value'}
What am I doing wrong here? In the 'scope' of the getToken call, I am sending:
audience:server:client_id:**i_put_my_clientid_here**. I have a clientid generated for "installed applications". Using this client id, the call to getToken doesn't work at all. When I generated a client id for a "service account", the call succeeds, but I get an 857 byte token that fails when passed to the TokenInfo endpoint as described above.
EDIT:
I also created a client id for "web applications", as it appears that is the right client id to use when calling getToken. But the behavior is the same, I get back an 857 byte token that doesn't validate when calling Google's endpoint.
How can I properly get a valid auth token using Google Play services on Android? Once I have the right token, what is the right node.js library to validate it server side? Can I use passport-google-oauth ?
Hm, this is really a comment rather than an answer, but I can’t put newlines in those:
it has to be the web-side Clent ID that goes in the put_my_clientid_here spot
if GoogleAuthUtil.getToken() gives you a String withou throwing an Exception, it really ought to be valid. When you hit tokeninfo, did you use ...tokeninfo?id_token=<857-byte-value-here>
if you’re a rubyist, grab the google-id-token gem and see if it can validate your 857-byte token.
If you just want to read the contents of the data returned by GoogleAuthUtil.getToken then the process is very simple. The returned data is simply a JWT. So all you'd have to do is split the data by the . character, and then base64 (url) decode each piece.
It gets slightly more complicated if you want you want to verify the message's authenticity. Simply use your favorite crypto library to do the verification. The 3rd component of the JWT is the signature of the data and the Google certs are publicly available; that's all you need to verify the message.
For a week I have been looking into how to validate GoogleAuthUtil tokens received in Android Client application at Node.js server using passport.js
Finally I came across passport-google-token passport strategy which perfectly performs the task.
https://www.npmjs.com/package/passport-google-token
More details are present in the above link.
The official node SDK lets you do that now.
Here's the link: https://github.com/google/google-auth-library-nodejs/blob/master/lib/auth/oauth2client.js#L384
I'm not too familiar with the details of how Android works with respect to handing a token from the device to the server. My general impression, however, is that you don't go through the typical web-based OAuth dance. Instead, you directly call the "user info" endpoint, which will return the info corresponding to the user who holds the token, or reject the request if the token is invalid. There's some discussion on this related question:
validating Android's authToken on third party server
In effect, the token becomes a secret that is shared between both the device and your server, so its important to protect it.
There are a couple strategies for Facebook and Twitter that were developed to do similar things using tokens from iOS devices:
https://github.com/drudge/passport-twitter-token
https://github.com/drudge/passport-facebook-token
You can take some inspiration from them and tweak it to talk to Google's endpoints. Let me know how this turns out. I'd love to see a similar "passport-google-token" strategy, so if you implement one, let me know and I'll link to it!

Categories

Resources