Android SSO (Single sign-on) for app - android

Is there any free single-signon mechanism for Android that gracefully works with non-webapps? Say, something along the lines of...
You launch my app and use it until it makes a request from the app server that requires authentication. It responds to that request with a random token that the server will associate with you for a short time.
The app presents you with a username field, a password field, and a submit button.
You enter your username and password. The app then forwards your username and hashed password, along with the token generated by the app server, to the login service.
The login service determines whether or not your username and password are valid. If they are, it digitally timestamps and signs the token, and returns the signed token to the app.
The app relays the signed token to the server.
The server checks the signature, satisfies itself that it's valid and signed by an authority it trusts, and proceeds as though the user had presented IT with a valid local username and password instead.
I suspect I'm just getting lost in nomenclature, but the impression I've gotten so far is that all the usual SSO providers -- Twitter, Facebook, etc -- only allow users to log in using a normal browser, and that you're either not allowed to do what I described, or they do something to make it effectively impossible with anything besides a normal browser (like dynamically creating the login form via Javascript in an effort to prevent developers from trying to use their own apps as a login facade).
Alternatively, does there exist any workflow like THIS...
You launch my app and use it until the web service requires you to log in. The app server generates a token and returns it to the app.
The app spawns a new browser via intent that sends you to the login provider's web site, passing the token via intent to the browser (and ultimately the provider) as a POSTed formvar.
You log in using the browser window, and the browser window closes -- returning you to my app.
The login provider signs the token, then sends it directly to my app server via HTTP POST so I can note its submission, verify the cert, and treat it as though it were instead a valid username and password submitted directly by the user to the app server himself.

Have you tried or think of using Firebase? https://firebase.google.com/docs/auth/?hl=es-419
It has some useful tools, you can sign-in with multiple social connectors and user/password as well, and they provide a library to integrate the whole UI and server flow, they even take advantage of google smart lock for you.
Take a look at https://github.com/firebase/FirebaseUI-Android I used it in a personal project and saved me a lot of time.

What you described in Alternatively section looks like Authorization Code using Proof Key for Code Exchange (PKCE) OAuth 2.0 grant
https://www.rfc-editor.org/rfc/rfc7636
The flow is the following:
Your app generates a random key (code_verifier) and it's transformed value (code_challenge) and navigates to authorization server with code_challenge as a parameter
Authorization server redirects back to your app with authorization code
Your app sends authorization_code and the code_verifier to the auth server to get the authorization token
Server uses authorization_code and the code_verifier (it already has code_challenge, so it can verify that code_verifier is correct) and then returns to your app with the token.
On the practical side of it you can use something like Auth0 to implement it in your app.

Use Android Account Manager for SSO.
Providing references below just for knowledge. You have to dig into account manager.
Android developer: https://developer.android.com/training/id-auth
Blog with example: https://www.zoftino.com/android-account-manager-&-create-custom-account-type

Related

Facebook Login with existing authentication system: how to pass the api token to the client?

I'm working on an Android app where there is an existing authentication system, based on email/password.
Whenever the user successfully logs in with username and password, a JWT token is created and returned to the app for making the authenticated calls.
Now I want to support Facebook Login, however some steps of the OAuth communication are not super clear to me. I searched the documentation but it seems to be a bit vague.
This is the process as I envision it:
User clicks on Facebook button
The app asks to the server a state token 821379812739871293 and calls the FB url configured like so
https://www.facebook.com/v3.2/dialog/oauth?client_id=123&redirect_uri=https://<myappdomain.some>/fb-callback&state=821379812739871293
The app opens a webview where the user can accept to login and share the email address
Facebook redirects to redirect_uri with something like this https://<myappdomain.some>/fb-callback?code=h21i3i2h13&state=821379812739871293
Within the callback call, the server:
checks if state token exists otherwise it rejects the FB callback
it uses https://graph.facebook.com/v3.2/oauth/access_token to obtain the access_token
it uses the FB APIs to retrieve the email address (have to check how to do this, but should be enough to call /me)
if email exists (sometimes it does not) it tries to find an existing user in the DB or adds a new one
[ UNCLEAR PART ] The callback returns a redirect to some OS-registered URL like http://<myappdomain.some>/login-success?apiKey=<jwt-token>
[ UNCLEAR PART ] the app reads the API key from the URL and proceeds making the calls to the backend
Is this correct/common practice?
Thanks!
EDIT: to clarify, I've seen this answer, however it is bad practice to store the client secret on the app side.
Moreover, in future I might integrate Instagram and LinkedIn authentications which seem to not allow or discourage bypassing the server with implicit oauth.

Secure the Auth Code in Oauth2 with native apps (Android)

That question is hardly related to AppLinks assetlinks.json appears not to be used for validation
I am implementing Oauth2 apps on Android. I would like to do SSO (single sign-on) and I have a concern about AppLink to secure the Autorization Code.
The native app, through the browser, initiate an Authorization Request and then receive an Authorization Response containing the Authorization Code. According to RFC6749#section-4.1.2, the code is passed inside the URL:
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
Authorization Code is a sensitive piece of information because it allows a client to fetch an Access Token and Refresh Token and then access to a protected ressource.
To protect that code, the native app must implement https scheme redirects (RFC8252#section-7.2 & section-8.1). On Android, that must be done using the assetlinks.json file
But according to the related question linked at the top, app links on Android seems not to be 100% secure, because the OS may not verify the https scheme.
In that context, how are we supposed to implement Oauth2 authorization code hook ?
EDIT
According to #benjamin anwser, AppLink is not for security. But, the related threat use-case is the following : a malicious app is installed and uses the "SSO Cookie" to get the Auth Code and exchange it for AT+RT. It seems to me that nothing in the process can prevent that case: if applink is not for security, how does the Authorization Server can be aware that this app is a malicious app ?
Note: By SSO-Cookie, I mean the use of CustomTab to do SSO on Android.
It's not the AppLinks functionality that guarantees security. When you configure the /.well-known/assetlinks.json file it allows a transparent redirect to the application without any user interaction. This means that the modal dialog that usually appears to chose which application the user would like use to handle the link won't pop.
As you stated, this mechanism can be bypassed if the user chooses to handle your link with another app or your app is not yet install. The user needs to go to the phone setting in order to achieve this :
Settings > Apps > choose the application which can handle the Authorization Code link > Open by default > Open supported links in this app > choose Always allowThis way a third party application can catch the information contained in your link, in your case the Authorization Code.
That been said, it's actually the Proof Key for Code Exchange (PKCE) that guarantees security of Authorization Code. Your server must implement this feature in order to mitigate unwanted Authorization Code replays.
A little reminder on the OAuth authorization steps using PKCE :
The client (application) calls the /authorization endpoint with a hashed random string and the method which was used to hash it. The client keeps the random string (not hashed) because it will used in the step 3.
The authorization server checks if user entered a right login/password. If all it's good, it stores the hashed random string and it's hash method which were sent in the request. The server then redirect the user agent to the application with a redirection containing the Authorization Code.
In order to retrieve it's Access Token, the client (application) calls the /token endpoint with random string generated in step 1.
The server receives the /token request, extracts the random string and hashes it with the method stored in step 2. Then the server must checks that this hashed string matches the one stored in step 2. If the strings are the same, the server responds with an Access Token and a Refresh Token, otherwise with an error.
This is how the PKCE ensures that the client that made the /authorization request it's the same client that will make the /token request. So even if a third party app captures your Authorization Code it can't use it to retrieve Acess Tokens.
For more informations see : PKCE (rfc 7636) and OAuth 2.0 for Native Apps (rfc 8252)

WSO2 Identity Server: How to handle Android App login with Google

Currently, we have the following landscape: a back-end (Play + Scala) server that provides a RESTful API. In addition we have a front-end Web client and an Android native app client. Now we want to add the WSO2 Identity server (v 5.1) to maintain user logins everywhere.
The problem that I am facing is with the native android app integration. I have a successful Google Sign In and as a result I have the Open ID token. According to https://developers.google.com/identity/sign-in/android/backend-auth I should send the token to my back-end server (WSO2IS) where the token should be verified against Google authorities and if the token is legit, it should sign in my user in WSO2IS. Note that if such user doesn't exist in our system, it should first be created and then signed in. Unfortunately I don't find a way to send the token to WSO2 Identity Server.
What I have done so far:
1) configured Identity Provider (IDP Google Federated Authenticators)
2) configured Service Provider where Local & Outbound Authentication Configuration points to previously defined Federated Authenticator Google
3) configured some claims in both IDP and SP
Then I start playing with the endpoints:
/oauth2/token
/oauth2/authorize
But using this is not what I want, because these endpoints will generate me a new token instead of getting the one I have.
Then I found out about Open ID prompt=none (http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest), and I also tried to invoke authorize and pass the open ID connect as Authorization: Bearer <token> header when I call
oauth2/authorize?prompt=none&scope=openid&client_id=fzOPC3fCftkgC3xcLn7ZqjXiY_Ya&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A9443%2Fcommonauth
Also tried none+login.
Is it possible to do this with WSO2IS? To register/login a user by passing a Google Open ID token?
If it turns out what I am trying to do is not possible, I come up with the following workarounds:
1) Create a custom service that will validate the token and if legit will register a new user. This is just an idea, I don't know if it is possible and also if I need to write the code myself why should I use the WSO2 Identity Server?
2) In the Android App I should drop the native Google sign in support and use a WebView where we will use the pretty clear and standard Web App flow. I cannot evaluate what I will lose by using web view instead of the API, but it seems wrong. It is natural that on Android phone you should sign in seamlessly with your Google account.
If I need to use one of the workarounds, please advise me which one is the better approach? Or propose a new one.
EDIT 1: Workaround 2 discarded based on
Browser popups is the preferred way for web apps to redirect the user to the IdP. Mobile apps on platforms such as Android or iOS should launch the system browser for that purpose. Embedded web views are not be trusted, as there’s nothing to prevent the app from snooping on the user password. User authentication must always occur in a trusted context separate from the app’s context (e.g. the browser).
This is taken from http://connect2id.com/learn/openid-connect#auth-request
If it is not possible to use a WebView (for security reasons) and in Android you can only open the browser, but you cannot command it with startActivityForResult. This means that even if the user sign in, the browser won't close automatically and it will hand out there until the user close it. In addition the browser won't tell your app that the user is logged and the app should find out by itself (honestly I don't know how: you cannot do server push or something similar, because you can sign in with the same Google account on multiple devices; and the second obvious option is server polling but the app doesn't know for which user to ask).
EDIT 2: A new view over things
When configuring Google for a Web Client login, there is a field for authorized URI (the callback that Google invokes to send the token back). For WSO2IS, this is https://localhost:9443/commonauth. So, this should be the URL that we need to send back the token in the Android app. I start testing with Postman, I am sending the following request:
POST /commonauth?code=eyJhbGciOiJSUzI1NiIsImtpZCI6IjhhNDJhODMzN2IxMmI5MzI5NGIyNGU5NDY5ZTViZWIwZGFhMWJlNGUifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJpYXQiOjE0ODQ2NDczNjIsImV4cCI6MTQ4NDY1MDk2MiwiYXVkIjoiNTM3ODQyNDY1MDM4LWpwZjRpYmE0cGI4YjN1bWY2aGhpYTFnNTJuODR1N2k1LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTAyMjMwNjU1MzQxMzczODU4NDI2IiwiYXpwIjoiNTM3ODQyNDY1MDM4LXJmYmt0YTJ0MWFlazgycDZrNzloNXZrb2ppcXVvMTQ0LmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwibmFtZSI6IkRhbmllbGEgVmxhZGltaXJvdmEiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1YQlNmUXgweE4xcy9BQUFBQUFBQUFBSS9BQUFBQUFBQUFBQS9BS0JfVTh0eTQyZHpfdk5sUFZ2Z01jcjUxUVJBWXBWMjNBL3M5Ni1jL3Bob3RvLmpwZyIsImdpdmVuX25hbWUiOiJEYW5pZWxhIiwiZmFtaWx5X25hbWUiOiJWbGFkaW1pcm92YSJ9.VMspUYeaAVHavEyoK3Hsss0pyZMHu-4QozucTAU-CLXnjAoaFbPBirslX7VpS4wvwHPge0AE5gHpIzAl1el_ufkhiu2NJn_LKo48Ve3HNj9igjnwD2nW_PGOqlYPoWV5UtFlKyUxi72qvLOCkYwsPuKVzA9irD-vGm3U2U3wBu_OQrJzbhdU9lp3aG4F0tQgQi-NPtEZY7Xgu-Om3qmarByhJYjxBPHEWzuyuQ2F9xY65t0mnd7gVAr2F5_aBHemjVx8V9lQc4eyRFjE3g_9ZgYn9xX9w8TwCXO9VpkdVRdFWQ07RFjFz915FO5KX9x4UNAu6H1Jop9ug5oiVCrmFw HTTP/1.1
On server side, this result in an error: Context does not exist. Probably due to invalidated cache. In server logs I found:
DEBUG - Session data key is null in the request {org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.DefaultRequestCoordinator}
ERROR - Context does not exist. Probably due to invalidated cache {org.wso2.carbon.identity.application.authentication.framework.handler.request.impl.DefaultRequestCoordinator}
I've looked at the code for DefaultRequestCoordinator, it seems I need 2 more parameters: type and sessionDataKey. I think the type should be set to openid, but how can I get a valid sessionDataKey?

Using Node's Passport to authenticate an Android app

I have a fully functional web app, where authentication was created using Passport. The application uses client-side, cookie-based session token. Basically, when a new session happens, the client's data is stored as Base64 AND signed client-side, so that the user cannot change it.
The login/pass mechanism obviously works 100% fine. Facebook, however, doesn't. The main issue is that in a web environment, the user is expected to get redirected to the Facebook page and which is passed the redirect URL to which the token is passed etc.
In a App environment, this doesn't happen: my (basic) understanding is that the client handles the whole oauth mechanism, and it is meant to provide the server with the userID and auth token -- which must then be checked by the server using a Facebook API.
So... is there a known "path" to go from "Web based Facebook login using passport" to "App based Facebook login using passport"? Or shall I not bother with Passport at all for the app side of things?

On Google App Engine, can I relate a Google OAuth 2 Token and a SACSID token I got using Android's AccountManager?

I am writing a Google App Engine application along with a CLI client, an Android client and a Javascript client. The purpose of this application is to allow one to control an Android phone on which the Android client is installed, by using either the CLI or the Javascript client.
Authentication plays a crucial role as a bug might allow a malicious user to control others' phones.
The Android client is written and works. It authenticates the user using this method. Basically, this give me a so-called SACSID token I can store in a cookie. When this cookie is set App Engine recognizes my user. The server application can then call the UserService to get a User on which to call getUserId(). getUserId() returns me an opaque string that identifies my user. So far so good.
Now I am writing the JS and CLI clients.
Because the CLI client has no reliable way of displaying a CAPTCHA or opening a browser, I suppose that it needs to use the Device API ("Client login" is not an option). This API requires using OAuth 2 for authentication. Also, I want the JS client to access the user's contacts, which also seems to indicates that OAuth 2 would be suitable.
If my user authenticates using OAuth 2, will I be hable to somehow transform this Google OAuth 2 token into the same opaque String that I get when the Android client connects ? If not, can I modifiy my Android Application so that it uses OAuth instead of a Sacsid token ?
To be more specific, I see three things that would solve my problem :
A way of getting an OAuth 2 token from the Account Manager
A way of exchanging the OAuth 2 token for a SACSID token
A way of getting the same opaque UserID both with the SACSID token and the OAuth2, but only if I can have both authentication system on the same application.
Something that seems similar to the third possible solution is to get the user's email address from both OAuth and the SACSID token, and to use that as the user ID. This however looks a bit clumsy to me :
Every time I receive an OAuth 2 request, I would need to call Google APIs to retrieve the user's email address (or build my own system of tokens which seems insecure and introduces many other difficulties).
The email address of a given user can change, making me lose the association between the user and his previous data.
Use End Points instead:
https://developers.google.com/appengine/docs/java/endpoints/
They use oauth2, they are easy to implement and have support for android IOS and Web.

Categories

Resources