I have 4-5 Android applications and I want to implement Single Sign on for all these apps. So that if user has logged into any one of that apps he won't be asked to log in again for other applications. How can I accomplish it in Android??
Implementing a SSO requires having a common database holding the user credential information. One way of doing it is implementing your own authentication server which exposes a login, register, reset and forgot password APIs which each of your apps would use to login into the application.
Lets say you are using JWT to maintain statelessness, which means auth server responds with a JWT for every successful login through any android app.
So your launcher activity in each of your app should not be login but the dashboard or whatever the user sees after login. In the on_create of the dashboard, check if there is an existing jwt available in the shared preferences. If there is one, go ahead with the dashboard. But if there isnt one, goto login activity and let the user login first. Once logged in, preserve the jwt in shared preferences for the other apps to use it. You need to make sure that all the shared preferences are using the same namespace to access the jwt.
To make it more effective, you can implement a library module for login, regd and forgot password to be included into each app and you would have that part for all the apps ready. The XML files for three activities can be included into the lib itself and app will load them from the lib file if it doesnt find it in the app drawables.
Now coming to server part, implementing your custom auth server, say using OAuth2 is one way but to make it easier, there are 3rd party solutions like Stormpath or CAS which would provide such a service. May be you can find one which is free too.
Instead of JWT, you could use userId (primary key in the user database) to identify if the user is logged in or not.
Another point to consider is if the application server for each of these apps, if they have one, are using JWT or userId to respond to app requests and based on that auth server communication token should be decided. Needless to say, that application server and the auth server should also communicate among them to sync user information for app. This would be the same even if you are using a 3rd party auth server which would talk to a single database holding the entire user information but you might need to work on syncing your application server with 3rd party auth server
However, the tricky part is in logout and reset password and change password. I am not talking about the logout process if JWT is used, which has its own challenges to meet, but I am talking about the logout when SSO is used. If the user logs out from one of the apps you need to decide if the user has to be logged out from the rest of the apps or not. Both can be handled though but usually it would be a single sign out for ease of implementation and it would provide a good UX too.
Also, if any of these apps has a website version and the user changes or resets password from the website, you need to make sure that user logs in again on the device when he first uses the app after the change. However this logic has to be managed entirely on the server side inside the auth server.
Though your question is related to android app only, you might have to implement a server for that and modify the appl server too for each of the app. There might be a chance that this might not be your question essence entirely, but your actual requirement might help me to help you implement this.
Related
I would like my app has the following feature:
User login with username and passowrd when first time install the app on phone. After successfully logged in, everytime when user launch the app again, the app doesn't ask for login credential again, but directly shows the landing screen. (Of course if user clear app data, the app will ask for login again)
The way to implement the feature in my mind could be that the app stores username and password in SharedPreferences once user login successfully, then, when user launch the app again, my code could check if there are username and password in ShareadPrefereces, if so, directly show the landing page.
My question:
I am not sure whether it is safe or really a good practice to store user's login credential in SharedPreferences? If not, what is the best way to implement this one-time login feature?
(I am doing it for both Android and iOS. So, I would like to hear both Android good solution and iOS solution. Thanks!)
It's a bad practice to store credentials in SharedPreferences. In fact it's bad to store credentials anywhere on user's device.
Using some encrypting library, for example Hawk for android would be a better, but still not recommended option.
Better way would require some work on the backend side: in return to user's credentials server would return a token which can be used leter for authorization. The token would expire in some fixed amount of time (like day, week, etc.). Before this time passes you can make another request and update your token for a new one which will live another week (day, month etc.)
Even better approach would be to save the token using Hawk (or some other similar lib)
Background
We have developed a web application featuring a rest-api using oauth2/oidc and support for third party apps
We have developed our own native apps for android and ios. Currently they retrieve a long lived token from user credential flow (no consent screen needed).
We are currently extending our authentication flow to also accept external login by google/office365. This is also supported by specifying acr value in authorization code/implicit oauth flow.
Issue/Problem
We of course want to be able to fully trust our native app and not show a consent screen for the best user experience. While using the authorization code/implicit flow though nothing can be considered a secret and a malicious hacker could potentially exploit (without user knowledge) the user if no consent screen is shown.
How can we avoid having to show consent screen for our own native app while still being sure user is as safe as possible?
How to solve?
Doing a separate office365/google login to retrieve refresh token from this idp and then implementing a way to publicly authenticate using this token to retrieve a longlived token from our webapp.
Simply ignore security flaw and never ask for user consent given the nonsecret mix of `clientId/clientSecret/redirectUrl` with the excuse "it's quite difficult to hack this".
Ignoring security flaw if external login with the excuse "google/office365 should show a consent screen anyhow when requesting a refresh token".
Some unknown way to make sure that its not a malicious app/user
The reason i don't like (1) above is it both opens up a somewhat new authentication flow in our webapp and forces native app to implement a more complex authentication flow.
Is there something im missing here, what would be considered best practise?
The point is that Google needs to authenticate the user outside of your app to make sure your app does not see the user credentials and thus defeat the purpose of OAuth.
The user also needs to allow the app explicitly to avoid random apps obtaining tokens from the user: anyone with a Google account can create a client_id/client_secret/redirect_uri combo. You/your app is not trusted by Google with tokens for arbitrary users without asking those users first. As you mention at (1) the user only needs to go through this once. The app may retrieve a long-lived refresh token and keep using that to refresh access tokens.
Hence best practice is to spawn a browser/webview and handle the authentication/consent flow in there. There's no way around that. If there was a way it would be a vulnerability because the system was designed to avoid it.
I'd say something like nr 2:
Have a way to mark a client (identified by clientId and clientSecret) as trusted (e.g. with a superuser interface), and thereby automatically give consent.
The client secret should be safe; if it's not, you have other security problems.
We're developing a REST based API that developers would call from their mobile apps, e.g. google play apps.
How can we make sure that the app developer doesn't steal the users user/pass by storing them or sending them to "EvilServer".
If we do not trust the app developers, does a technical solution to this problem exist?
Could one solution be to have our own trusted authentication app on the native platform and let app developers use it to authenticate?
What I would recommend is to first remove the ability for a third-party application to log a user to your service using his credentials, so there is no reason for an app to ask for the user's credentials in the first place.
I would instead provide an OAuth authentication endpoint (take a look at the server-side flow) to third-party developers in order for them to use your authentication service to register and authenticate users in their app. This is interesting because users have to be redirected to your authentication endpoint when they log in, so there is no chance a third-party application can have access to their credentials at any point.
However, nothing prevents the developer of an evil app from creating a fake form requiring the user to provide sensitive informations in order to log them in, such as an email and a password.
In this case, you can do two things :
First, educate your users (e.g when they create their account) not to provide their credentials on any other website than yours. This is typically done by banks and insurance companies.
Implement Multi-Factor Authentication to add another layer of security to your authentication process. Most web companies such as Google or Twitter allow you to require that while providing your usual credentials when logging in, you are still required to validate the login process using an out-of-band medium. They typically achieve this by sending you a PIN code via SMS on your phone that you must input on a web page to finish the login process.
As such, if someone tries to log into one of your user's account, it will fail unless they have also access to the user phone.
OAuth attempts to solve this problem by sending the user off to a provider to authenticate before bringing them back to the original site or app. This is how the "Log in with Facebook" and "Log in with Twitter" systems work.
There's a handy diagram at http://www.quora.com/How-does-Login-with-Facebook-option-work-on-third-party-websites that shows how the requests are passed back and forth.
I want to maintain user session once the user logs into his/her account so that they are logged in even after the application is closed and started again. Searching on Google and SO, people referred SharedPreferences. I understand that I have to store user details in SP(SharedPreferences), but what if the user updates his/her data? Plus, the HttpGet call I send to the link to get user data returns the valid data(JSON) only when the user is logged in. Is SP the only way to do this, or is there other and more efficient way to do this?
P.S. - I am working as a freelance for a startup, and they have API to their PHP website. I have to make an android app for their website. To log in the user to the website, I make a Http POST call to their API and the result I get is a JSON. If the JSON contains "success" value to the "result" key, then the user is logged in. But as soon as I use intent to go to the next activity(where I have to display the user data by making Http Get call to another API, which only works if the user is logged in), the session is lost. Since I work as a freelance, they don't really trust me giving cookies to user sessions. So, I was hoping there might me some other way?
You can always use cookies (with, say, an authentication token?), Android OS manages them for your app automatically - as long as the cookie is correctly set by the server (ex. expiration date) your app should work fine. But this is a little old school.
A more modern way is to use OAuth or integrate an already existing login system (Facebook, Google, etc.) to authenticate users.
Using Shared Preferences is a wrong tool for this job. It's a workaround for doing proper authentication. There are ways that are trustworthy and secure and take care of all kinds of edge cases, and while it takes a little bit of work to set up, it's a much better option, IMO.
You should try to integrate android AccountManger APIs because storing the credentials in shared preferences is not especially desirable from security point,especially if your app is going to run on rooted devices.
From the docs:
public class AccountManager extends Object java.lang.Object ↳
android.accounts.AccountManager Class Overview
This class provides access to a centralized registry of the user's
online accounts. The user enters credentials (username and password)
once per account, granting applications access to online resources
with "one-click" approval.
Different online services have different ways of handling accounts and
authentication, so the account manager uses pluggable authenticator
modules for different account types. Authenticators (which may be
written by third parties) handle the actual details of validating
account credentials and storing account information. For example,
Google, Facebook, and Microsoft Exchange each have their own
authenticator.
Many servers support some notion of an authentication token, which can
be used to authenticate a request to the server without sending the
user's actual password. (Auth tokens are normally created with a
separate request which does include the user's credentials.)
AccountManager can generate auth tokens for applications, so the
application doesn't need to handle passwords directly. Auth tokens are
normally reusable and cached by AccountManager, but must be refreshed
periodically. It's the responsibility of applications to invalidate
auth tokens when they stop working so the AccountManager knows it
needs to regenerate them.
\
I'm intested in building some kind of password-less login between a mobile app and an API (assuming I can control both). The motivation is that having to login is very annoying for users and has security risks (eg. users will reuse existing passwords) and I want the users to be able to get started with the app immediately.
I'm wondering if there are some techniques that could work. For instance:
Generate and random login/password on the mobile device and store the password in the keychain.
Signup with the API using this login/password combination. This returns a token.
Token is used in subsequent calls
The drawbacks are:
Login/passwords can be lost if user deletes app (this could maybe be mitigated by using iCloud to store the login - but that would be bad for the password?)
Password is stored on the device (however it's in the keychain)
So my questions: is something like this feasible and secure enough? Are there known techniques to do that?
Here's what we did:
Basically, the idea is pretty similar to the "forgot password" most services offer:
Ask the user for an email
Send an email with an activation link. The email contains a deeplink with a one time token, something like myapp://login?token=......
User opens the email on the device where the app is installed this is crucial for the deep link to work, but it what happens on 99% of the cases anyway. The user clicks the button with the deeplink
User is redirected back to the app, you extract the token from the deeplink on the app and send it to the server api to authenticate. After authentication is done, create a session for the user so they won't need to authenticate again
The good:
More secure: Users don’t have to think of new passwords (which are usually too simple) and there is no risk of users reusing passwords. For us as developers, it offers a solution that has only one (and simple!) path of authentication that is easier to understand and hence to protect. Also, we don’t have to touch any user passwords / hashed passwords.
Smoother onboarding flow to the user: if you pre-enter the email in the input field the login flow can be as short as 2 button clicks and they're in. (unless you wanna take their name / other details as well but that requires additional input fields in traditional login as well)
The less good :)
Users might not be used to this flow very well and might wonder why they don't need a password. I would add a small link explaining "why we don't need passwords?"
If app is deleted or the user logs out, they will need to use their email to log in again. This is less of a problem for mobile apps where users don't occasionally log out and in etc
I've already implemented this flow into our app, you can read a more in depth explanation here:
http://www.drzon.net/passwordless-login-in-mobile-apps/
Some more considerations:
To make it more secure, make the token available to use one time only and also put an expiration on it (like an hour). You can also tie the token to the specific device by sending the server a unique device id of some kind along with the email address. This way the user can't simply forward the email to another person and he will open it instead
About the deep link - I found that some email providers block the use of links with custom url schemes like app://. The way to overcome this is by making the link point to your server instead and redirect there to the actual deep link
https://myserver.com/login?token=... ---> myapp://login?token=...
Mozilla wrote about it as well here
This is very open ended, but generally: don't reinvent the wheel, use a standard solution such as OAuth and/or OpenID Connect (uses OAuth). This has the drawback that users might required to login via a WebView or similar to get a token, but you won't have to store the passwords.
Things to consider:
you can't really generate a random password, since the server needs to know it as well
Android doesn't have a public keychain-like API, so you have to take care of securing the password yourself.
As for 'secure enough', pretty much everyone uses OAuth nowadays(Twitter, Facebook, etc), so it's at least proven. The actual security will depend on your particular implementation.