react native android oauth2 - android

I am developing a react-native application, in this application im trying to authenticating using oauth2. Now im trying to use a webview to retrieve my redirect_uri credentials, but im unsure how to retrieve it in react-native on a Android device.
I have found a example but it doessnt explain how to get the acces token in a variable, and I dont know how to implement this inside react-native.
for this purpose I am trying to use a implicit flow.
Grant Type: Implicit
The implicit grant type is used for mobile apps and web applications (i.e. applications that run in a web browser), where the client secret confidentiality is not guaranteed. The implicit grant type is also a redirection-based flow but the access token is given to the user-agent to forward to the application, so it may be exposed to the user and other applications on the user's device. Also, this flow does not authenticate the identity of the application, and relies on the redirect URI (that was registered with the service) to serve this purpose.
The implicit grant type does not support refresh tokens.
The implicit grant flow basically works as follows: the user is asked to authorize the application, then the authorization server passes the access token back to the user-agent, which passes it to the application. If you are curious about the details, read on.
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
Integrate oauth2 with native (iOS/Android) mobile application
My question is what should my redirect_uri be?
How can I retrieve the variables on react-native Android?
Is 'implicit flow' the way to use on a mobile application?

First you start looking which oauth2 flowtype is the securest one for your application in question by looking what other recommend.
After that I looked at 'implicit versus password grant_type' and looked up the fields which are required:
https://www.rfc-editor.org/rfc/rfc6749
I made sure a authorized endpoint is active for testing (by making one active yourself with the correct grant_type) Next I wondered how to fill all the fields. By installing postman, i could analyze and make a POST call myself.
After that you look up your url which in my case was : localhost:8000/oauth/token
and post against it using postman.
I was stuck on the part that you can't use JSON on the request body, but instead the oauth request needed to be in 1 long parameter called 'body' as a string. This is the way a httprequest works.
//authorization grant type: Resource owner password-based.
const HOST_ADRESS = "192.168.104.137:8000"; //change with your own host
const client_id = "jpijpijpijpijipjipijipijipijipj";
fetch('http://'+HOST_ADRESS+"/oauth/token/", {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cache-Control': 'no-cache'
},
body: "client_id=sfjwepifjpfweijgpeijSGIOEJOPGIWSJA35340537530708&grant_type=password&username="+username+"&password="+password
})
.then((response) => response.text())
.then((responseText) => {
console.log(responseText);
//redux succed do something.
//dispatch(actionsCreators.succesLogin(responseText));
})
.catch((error) => {
const data = {error: "A error happened"};
//redux error.
//dispatch(actionsCreators.errorLogin(data));
console.warn(error);
});
Hopefully someone else learns something coming across the steps I took.
Only need to save the token somewhere in a database to check (sql lite ) or realm.io (yay for next steps.)

First, you should choose the right grant type based on where you are trying to log in.
If the service is yours, you can go with grant type password.
If the service is third party, you can use implicit type. You provide redirect uri, which has to be registered with that particular service and which is used to redirect user after he is authentized.
Finally, there is a network API in React Native where you use fetch (see docs). As a second parameter to this function, you can provide additional informations and header. This is where you set all the required informations provided in the oAuth2 docs.

This is a very interesting example: https://github.com/bartonhammond/reactnative-oauth-hapi

Related

Where to find identifier and secret for OAuth2.0 and what does 'imaginary functions' mean?

I'm following this documentation to implement OAuth2.0 in my flutter app and don't understand a few things, here is the code from the documentation:
import 'dart:io';
import 'package:oauth2/oauth2.dart' as oauth2;
// These URLs are endpoints that are provided by the authorization
// server. They're usually included in the server's documentation of its
// OAuth2 API.
final authorizationEndpoint =
Uri.parse("http://example.com/oauth2/authorization");
final tokenEndpoint =
Uri.parse("http://example.com/oauth2/token");
// The authorization server will issue each client a separate client
// identifier and secret, which allows the server to tell which client
// is accessing it. Some servers may also have an anonymous
// identifier/secret pair that any client may use.
//
// Note that clients whose source code or binary executable is readily
// available may not be able to make sure the client secret is kept a
// secret. This is fine; OAuth2 servers generally won't rely on knowing
// with certainty that a client is who it claims to be.
final identifier = "my client identifier";
final secret = "my client secret";
// This is a URL on your application's server. The authorization server
// will redirect the resource owner here once they've authorized the
// client. The redirection will include the authorization code in the
// query parameters.
final redirectUrl = Uri.parse("http://my-site.com/oauth2-redirect");
/// A file in which the users credentials are stored persistently. If the server
/// issues a refresh token allowing the client to refresh outdated credentials,
/// these may be valid indefinitely, meaning the user never has to
/// re-authenticate.
final credentialsFile = new File("~/.myapp/credentials.json");
/// Either load an OAuth2 client from saved credentials or authenticate a new
/// one.
Future<oauth2.Client> getClient() async {
var exists = await credentialsFile.exists();
// If the OAuth2 credentials have already been saved from a previous run, we
// just want to reload them.
if (exists) {
var credentials = new oauth2.Credentials.fromJson(
await credentialsFile.readAsString());
return new oauth2.Client(credentials,
identifier: identifier, secret: secret);
}
// If we don't have OAuth2 credentials yet, we need to get the resource owner
// to authorize us. We're assuming here that we're a command-line application.
var grant = new oauth2.AuthorizationCodeGrant(
identifier, authorizationEndpoint, tokenEndpoint,
secret: secret);
// Redirect the resource owner to the authorization URL. This will be a URL on
// the authorization server (authorizationEndpoint with some additional query
// parameters). Once the resource owner has authorized, they'll be redirected
// to `redirectUrl` with an authorization code.
//
// `redirect` is an imaginary function that redirects the resource
// owner's browser.
await redirect(grant.getAuthorizationUrl(redirectUrl));
// Another imaginary function that listens for a request to `redirectUrl`.
var request = await listen(redirectUrl);
// Once the user is redirected to `redirectUrl`, pass the query parameters to
// the AuthorizationCodeGrant. It will validate them and extract the
// authorization code to create a new Client.
return await grant.handleAuthorizationResponse(request.uri.queryParameters);
}
main() async {
var client = await loadClient();
// Once you have a Client, you can use it just like any other HTTP client.
var result = client.read("http://example.com/protected-resources.txt");
// Once we're done with the client, save the credentials file. This ensures
// that if the credentials were automatically refreshed while using the
// client, the new credentials are available for the next run of the
// program.
await credentialsFile.writeAsString(client.credentials.toJson());
print(result);
}
Where can I find the identifier and secret ? Is it shown in the /.well-known/openid-configuration page ? Also how do I implement these functions:
await redirect(grant.getAuthorizationUrl(redirectUrl));
var request = await listen(redirectUrl);
var client = await loadClient();
The documentation mentions that it is an imaginary function. How do I implement those functions?
OAuth with flutter is never going to be completely straight-forward on Android or iOS because it lacks deep integration with the OS, so you'll have to do a bit of per-OS configuration. And to be completely honest, it's not all that easy in native Android/iOS either.
And that plugin you're looking at seems much more focused towards a server application, which is why it doesn't make complete sense to a flutter developer. However, it isn't impossible to use it!
The main thing that enables OAuth to work is using either a Custom Url Scheme or a Universal Link. A Custom Url Scheme is something like com.myapp.customurlscheme:// - it's used instead of 'https'. A Universal link uses https and a website i.e. https://myapp.com/customurl/. An important difference is that to use a Universal link, you must control the website and upload a file that apple can check to know you've given the app permission to replace that website or that part of the website. If the user has the app installed, they will be shown it when they go to that url; if they don't, they'll be shown something by the website (normally a link to install the app).
In the case where you're an authenticating client with OAuth, you normally don't want to be replicating part of a website as all you're doing is making a callback (redirect) url, so you'll probably be using a custom url scheme. This has to be done by adding to either your AndroidManifest.xml or Info.plist files.
For iOS's Info.plist that looks something like:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>[ANY_URL_NAME]</string>
<key>CFBundleURLSchemes</key>
<array>
<string>[YOUR_SCHEME]</string>
</array>
</dict>
</array>
And for the AndroidManifest.xml something like:
<activity>
...
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="[YOUR_SCHEME]"
android:host="[YOUR_HOST]" />
</intent-filter>
Once you have that set up, you can add listeners natively for when the app is 'opened' with one of those custom URLs. That's a bit of a pain, but thankfully someone has made a plugin that helps: Universal Links (and credit to them for the sample config above as I shamelessly stole it from their documentation). You can use its getInitialLink() method in your main function (or somewhere like it) and/or get a stream of links to listen for using getLinksStream(). I think that the second one is what you'll be using since the app is open already when you start the OAuth/OpenID workflow - so you'll start listening either right after the app is opened, or right before you start with the OAuth call.
Okay, so that was a lot. There's a reason for it though - what this has done is made a way for your app to receive redirects from a browser or other app. So if you handle that getLinksStream, you can then more or less receive a callback from the oauth2 server. You could set up some system where you create a future that waits for a particular link being passed through the linkstream.
So that covers
// Another imaginary function that listens for a request to 'redirectUrl'.
var request = await listen(redirectUrl);
Now we need to do something about that first imaginary function. Turns out in the app case, it's not imaginary at all - you need to launch that URL rather than having the page redirect as it would on a server. There's a plugin for that: Url Launcher
So where it's saying await redirect(grant.getAuthorizationUrl(redirectUrl));, what you actually want to be doing is launching grant.getAuthorizationUrl with url_launcher's launch() (with appropriate flags, that you'll have to figure out by testing. You may want to force using a browser, or not, depending on whether the OAuth server has an app that can handle auth for it. If they do, you probably want the url to open up in their app so the user is already logged in).
There's a couple more pieces to this puzzle that need to be fit in. The first is the redirectUrl that you have to pass into getAuthorizationUrl. What do I put in there, you ask?! Well, you use that nifty custom app scheme we set up earlier! So the redirect url will be something like com.myapp.customurlscheme://customurlredirect.
So the OAuth token provisioning workflow goes something like this:
you launch the auth url for the server
a login page is shown to the user, or a permissions page, or whatever the server does
once the user has approved the request, the server redirects the user back to your app (it might ask them "Do you want to open in " or something like it).
Your app receives the callback with the authorization code
Your app should request tokens using that authorization code (I assume that's handled by handleAuthorizationResponse).
Now, before you implement all that, there are a few things to think about.
If this were a server application, you could have a secure secret which proves to the OAuth server that your application is the client it claims to be. You would get that from the OAuth server and provision it directly to the server. However, because you're writing an app there is no (easy) way to provision that secure secret. So instead of using the normal OAuth you should be the OAuth authorization code flow with PKCE, and no client_secret. If that went over your head, you should do some reading up on PKCE - Auth0 has a good writeup. The OAuth server you're working with also has to support that, but if you do this without it your login process will be insecure.
The OAuth server you're communicating with has to both understand and accept custom url schemes. Most of the big ones do and they actually have documentation similar to this which should walk you through the same process (but not flutter-specific). And in fact they actually define what the custom url schemes should be - in Facebook's case if your app id is 1234567 then the custom url scheme would be something like fb1234567://.
I haven't looked that much into that library you're using, but you may want to make sure it actually supports the right OAuth workflow. If it designed as a server-side package as I suspect, it might not. In that case you might have to manually do the setup - which realistically isn't that difficult, you just have to generate a couple of URLs to match what the OAuth server expects which is pretty well documented and standardized.
That was a lot of information, but unfortunately OAuth2 isn't all that simple (and realistically, it can't be all that much simpler if it is to do what it needs to do). Good luck with your app!

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

FB API request without user login

I want to get the events list from a public Facebook page, and to do it I need an access token. This is not a problem when doing it server-side, because I can use both my secret and client app id in order to get an access token, but this is not possible on client-side (for example, on an iOS application), since it would make clear my app secret ID. What can I do? With the Facebook SDK for iOS, I think I can only get an access token making the user log-in, but, in my case, this is not necessary, since I only need to get a public list of events.
With PHP:
require '../facebook-php-sdk/facebook.php'; //MY FACEBOOK SDK
$facebook = new Facebook(array(
'appId' => '<#MYAPPID#>',
'secret' => '<#MYAPPSECRET#>', //<-- I CAN'T USE THIS ON CLIENT-SIDE!
));
Thanks

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"

Categories

Resources