Overview
I am building a RESTful API application as mobile\web backend (let's call it MyBackendApp) and I'm looking for a contemporary solution for both Authentication AND Authorization of app users. Primary language for backend is Java. Looking at other apps, many of them offer several auth methods to user: using external to app account (e.g. Facebook, Google, Yahoo, OpenId etc.) or internal (email\password). Something like Stackoverflow has on its sign-up\sign-in. I read many sources about OAuth2, I also used to use Spring Security to implement internal user accounts and session management. But I'm having hard time putting both methods together.
Requirements
I want user to be logged in using either of following methods
with external (possibly OAuth2) Facebook-like account
using email\password
Role Based Access Control to the API methods. The MyBackendApp will have following roles: app admin, content admin, content user, content creator, developer (for other apps to use MyBackendApp API)
Like all modern mobile apps I want user stayed logged in until expiration or session revocation (if to go as described below in Current implementation thoughts, then it can be done with token revocation). And I don't want him to get to login screen everytime he opens up MyApp's mobile app
Current implementation thoughts
OAuth2
For simplicity I use here Facebook term, but assuming more general meaning: the authentication with external to MyBackendApp account from any external Provider.
My understanding is that if user already have authToken from Facebook (he has already logged in with his Facebook app) stored somewhere in his mobile device, then just get the authToken (I believe I saw method in Android SDK, please correct me if I'm wrong). Otherwise, need to go through the standard OAuth procedure to receive the authToken from the provider (Facebook). Now, having the authToken and secret key from the provider MyBackendApp can retrieve a user unique ID AND email from the token and:
if the uniqueId is already in MyBackendApp DB, then user is authenticated
and MyBackendApp allow or don't allow access to a requested REST endpoint,
based on users (defined by its uniqueId and email) Role.
if uniqueId is not in the MyBackendApp DB, then user is going through MyBackendApp
registration process, which is similar to Stackoverflow sign-up. His info gets stored in the DB
user gets assigned some role
email\password auth
Sign-Up. If user is not registered, then he goes through registration process: MyBackendApp stores email and hash of password in DB. It also assigns a Role (lets say Content Creator)
Sign-In. If user is registered and want to log in
he enters email and password in a client app (WebUI JavaScript\Android\iOS)
client app (lets call it MyClientApp) gets hash out of password (please correct me if it's not a right way) and POST it along with email to MyBackendApp over https. Edit: there is no sense to hash the password on client side. Rather than that the password will be sent as is over SSL. After that Server (MyBackendApp) will generate a hash and compare it with stored hash in DB.
having email and password MyBackendApp authentifies the user and issue authToken (possibly JWT) with userUniqueId (UUID), some expiration date.
the authToken is to be sent on every REST API request
Next time MyBackendApp receives request to some of REST endpoints it retrieves the userUniqueId, expirationDate and based on Role allow\disallow the call.
Summary
Does the approach described in the "implementation thoughts" section above make sense? Any security threats?
Some posts says that OAuth cannot be used for user authentication, e.g. here, but I didn't get why? And if not then how to provide users login using facebook\google\others account?
I definitely don't want to reinvent a bicycle, so I'm wondering is there any framework which make this task easier? I believe that Spring Security with its OAuth2 support can help a lot for implementation of OAuth2. But how does it work for both types of login (OAuth2+email\password)?
This post suggests [Apache Shiro] - is it good for the described purposes? Can it be combined with Spring Security OAuth2?
I wrote above that having the authToken and secret key from the provider MyBackendApp can retrieve a user unique ID AND email - but is it the case? Do providers include this information in the authToken?
If user of mobile device or web browser has already got the authToken (e.g. he logged in in facebook mobile app OR desktop browser stored his password) and he's already allowed MyApp in Facebook once - can he open my app being already logged in with his facebook account skipping the login procedure? How?
Related
We have an already existing system which uses an old Auth0 server for authentication and authorization. My goal is to integrate this system with Keycloak. In the Auth0 server we assign roles to users and these roles are mapped to a group of permission scopes, eg, "account:create", "user:create", etc are assigned to role "admin". We are planning on using keycloak Authorization services to replace Auth0 authorization. For it to work, we need to use keycloak bearer tokens.
Problem is, several users make requests to our API using an api-key (fix token). We basically make a request to the Auth0 server with api-key and it returns permission for that user. As we can't ask user to change the way the interact with our API (managament decision), i'm thinking on creating a custom authenticator, so when I request token endpoint (http://{ip}:{port}/auth/realms/{realm}/protocol/openid-connect/token) with an extra api-key header, I can check if there is an user with that api-key attribute assigned and get a bearer token for that user in return. The idea is to do this internally.
Is it a correct approach? If so, how do I implement the authenticator? Once I have found the user by api-key, how do I tell the authenticator which is the authenticated user?
Better late than never! I resolved this a while ago, but I wanted to share the solution, in case it helps someone:
I saved the API keys as user attributes.
I created a custom Keycloak Authenticator that checks if there is an user with the given API key.
I created a custom direct grant flow to use the custom Authenticator that successfully authenticate the user either if an API key or usual username and password credentials are provided in the token endpoint.
As the user only knows about API keys, I used an eviction cache whose key is the API key and whose value is the bearer token.
You can find an example and more details in the following repo:
I would like to authenticate against KeyCloak using "Direct Access Grant": https://www.keycloak.org/docs/latest/server_admin/index.html#resource-owner-password-credentials-grant-direct-access-grants
I works like a charm when keycloak manages users and passwords on its own.
But, my scenario is different:
I would like keycloak to act a Broker to some external IDP. KeyCloak has identity brokering feature - but in only works in "Authorization Code flow" - redirecting user to external IDP login form.
I have mobile app and would like ot use "direct access grant" - so that app comunicates with keycloak to authenticate user - and keycloak, as a broker, authenticates this user (using openid-connect) in external IDP
How to achieve such scenario ? I know that it is not possible out of the box - but maybe somebody could advice how write an extension to keycloak do make this scenario possible ?
Whatever it is you are trying to achieve this way, it goes directly against what OAuth and OpenID Connect were designed for. The whole idea of using access tokens is to allow some relying party (such as a mobile app) to interact with a service on behalf of the user without ever getting to see the user's credentials (like a password).
Think of it like this. Let's say you have some app on your mobile phone. It can make use of certain services by Google. In order to do so it offers you to log in with Google and grant the app access. Now, would you want to do so by putting your Google email and password directly into the app? Of course not. That could give it complete control over your Google account, other apps and sites using your Google identity, possibly services that allow you to pay through your Google wallet... It would be insane to simply hand some phone app your Google login.
So instead with OAuth2 or OpenID Connect you can use the authorization code flow or implicit flow to have the user redirected to the identity provider (Google in our example) where they will complete their login process, and then the identity provider redirects back to the app or a site with an authorization code that can be exchanged for tokens or, for the implicit flow, the tokens themselves.
Now, when it's your own app and your own identity provider (like Keycloak) which are under your control it doesn't really matter. You can use a direct grant to simply have the user input their username and password into the app because you know it's not trying to steal user credentials to maliciously use your service. They're both under your control. In that case OAuth or OIDC are a bit overkill, but you could have separate clients for direct grants (your own app) and authorization code flows (third-party apps using your service). When you want to use Keycloak identity brokering, however, an external identity provider like Google or Facebook is not going to offer a direct grant and invite apps to steal their user's credentials. So you won't be able to interact with them this way.
Depending on what you're trying to achieve you may find some use in the token exchange process. If however the idea is that you want your user to log in with their external identity provider credentials, in your app, without a redirect... Don't.
This is a real use case, unfortunately Keycloak doesn't have a direct way of solving this issue. AWS's "IAM Roles for Service Account" feature works based on token exchange with direct access grant using external IDP. I found this discussion on how to workaround this lack of support in Keycloak but not sure if it solves all the usecases - https://lists.jboss.org/pipermail/keycloak-user/2017-January/009272.html
Do you stick with Direct Access Grant as a method of user authentication in your mobile app? In my opinion, you need to use Authorization Code Flow when the IDP is a third party service as it won't provide an API to authenticate users, and even with your own (first party) IDP, it'd be better to use Authorization Code Flow as stated in OAuth 2.0 Security Best Current Practice section 2.4.
To implement Authorization Code Flow in mobile apps, you will need to use in-app browser tab to show login screen provided by the IDP. Please refer to RFC 8252: OAuth 2.0 for Mobile and Native Apps for details.
I'm in in process of looking to create an Android app; security is obviously the most important thing to keep in mind.
What is the best-practice for authenticating a user and handling business logic (scenario below).
For example, the current design would facilitate the permissions based on the user's login. When a user logs in and successfully authenticates, their Username and Password are stored in session variables. When the user attempts to request a resource that requires a certain permission to view, as part of the process for accessing the resource their Username and Password is sent up to the intermediary Web Service, if this authenticates with the correct permission-set the resource is then accessible.
Is this a reasonable way of operating an Android application or is there a better solution to handling this?
Thanks.
Presumably you're referring to building some sort of web API such as REST API that the Android App would send requests to and the API performs the database actions.
I wouldn't send the username/password combo for every request that tends to be bad practice. You send the user/password combo once to authenticate and the authentication returns some sort of token and this token is then sent in every request and is validated on the API side to ensure it is a valid session token. You could either roll this yourself or use some sort of Single Sign On (SSO) solution such as Google Sign on for example or OAUTH is a common authentication mechanism. Maybe https://oauth.net/ will help.
I am reading lot of cognito documentation but the thing which is confusing is the limited documentation for build Hybrid applications(cordova mobile app).
This is my understanding so far:
I can develop my own sign-in and signup screens but use the cognito user pools as a backend authentication datastore.
or I can simply plug Cognito hosted webUI for sign-in, sign up.
1) If I have to use my own, I would have to use the Amazon cog SDK API to authenticate a user, validate email during signup etc .
2) If I need to use the hosted pages from amazon, I would need to configure it to redirect to my applications homepage.
probably follow this link -->> ?
https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-configuring-app-integration.html
Once the user is authenticated ,I would need to create session for logged-in user, decrypt the token which is a JWT to fetch all details about the user like user_name, etc & then tie this user to the same session.
When the user clicks on any other link in my web application, my authentication filter will need to check if the current session had any valid token and validate it. Question is how do I validate that the token in the cookie is the one which is valid and not expired. which API can be used to check if the token is a valid token.Would I need to go to cognito eveytime?
You would have to use Cognito SDKs to validate the token before you serve your resources. The SDK methods to verify the token will ensure that the token has not expired, the user belongs to the app, and to the specific user pool that is allowed access to your resources.
You can find more here - https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html
I have a API that is ran on multiple sites. The user can register via multiple social logins on these client sites. The one I will speak of is Twitter. How can I authenticate on the client website and api website that is the actual user? I am doing the api call via Javascript which someone can visible see what to send to the api request. Even if they do see it I want to verify they are using the access token for that username, not a fake one they are trying to send. Do both sides need to know the consumer key and consumer secret key to verify credentials? I have looking for the best possible workflow on how to do this during registration.
Have you considered utilizing something like JanRain Engage (http://www.janrain.com/products/engage) to provide your users with a simplified social login environment?
Disclaimer: I don't work for JanRain, just a fan of their products for simplification of social authentication.
I used a third party framework that calls verify credentials with the consumer key, consumer secret key, token access, and token access secret, and compare the userid of the result with the result in the request.