For confidential clients, there are scopes assigned to clients and the logged in user has to consent to them. Since there is client secret involved in exchange of auth code for access token, no one can impersonate them and take advantage of their scopes.
But when it comes to pkce flow on a native app, if I had someone else's clientId (clientIds are not considered private information) which has a lot of scopes, I could just start the flow with with their clientId. What is stopping a hacker from using some reputed clientId in the PKCE flow and have access to all their scopes?
NATIVE CALLBACK METHODS
If you look at RFC8252, certain types of callback URL can be registered by more than one app, meaning only a client ID needs to be stolen in order to impersonate a real app, as you say.
This still requires a malicious app to trick the user to sign in before tokens can be retrieved. And of course each app should use only the scopes it needs, and prefer readonly ones. After that it depends on the type of native app.
MOBILE
A mobile app can use Claimed HTTPS Schemes via an https callback URL to overcome this. It is backed by App Links on Android or Universal Links on iOS. Even if a malicious app uses the client ID, it cannot receive the login response with the authorization code, because it will be received on a URL like this, and the mobile OS will only pass this to the app that has proved ownership of the domain via the deep linking rehistration process:
https://mobile.mycompany.com/callback?code=xxx
DESKTOP
For desktop apps there are gaps, since only Loopback and Private URI Scheme callback URLs can be used. It relies on users to avoid installing malicious apps. Eg only install apps from stores that require code signing, which also inform the user who the publisher is. If users install malicious apps then perhaps they have deeper problems.
ATTESTATION
A newer technique is to use a form of client authentication before authentication begins. For confidential clients, Pushed Authorization Requests are used, which uses the app's client credential, so this cannot be used by native clients by default.
Mobile apps could potentially provide proof of ownership of their Google / Apple signing keys during authentication, and there is a proposed standard around that.
Related
I'm working on a native app which will use OAuth to allow the user to sign in (or access material itself) to another website. I know I'll be making use of the implicit flow or authorization code flow for OAuth, however all my research regarding security seems to relate to the client secret.
It seems to be the client id for my app (which is provided by the 3rd party site) will be public and therefore exposed. This would allow someone else to take it and, following the same implicit flow, masquerade as my application. Is this just the nature of oauth?
Is there a way of storing this information so it cannot be stolen?
EDIT:
I'd just like to clarify - I understand oauth keeps the user's information safe from my app and ideally interceptors. But what is stopping someone from taking my client id (as it is publicly visible through the auth process) and using it for themselves? Are any measures that can be taken defeated by open sourcing the app?
The client id can't be protected because it is send as a query parameter in the authorization request.
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
(You could use a web view inside your native app and hide the address bar, but then your app would have access to the user's credentials.)
Further explanations:
Using the implicit flow in native apps is not recommended, because an attacker could register your redirect URI at the OS and could catch the callback with the access token.
The authorization code flow is a better option. If you are able to store the client secret securely within your app (see link below), an attacker could use your client id to start the authorization or catch the callback, but he wouldn't be able to use the authorization code to get an access token.
Links:
Best practices for storing and protecting private API keys
How to avoid reverse engineering of an APK file
Best practices for implementing OAuth in native applications
RFC for PKCE
There appears to be four distinct flows in OAuth2, i.e. (link),
Authorization Code Flow - used with server-side Applications
Implicit - used with Mobile Apps or Web Applications (applications
that run on the user's device)
Resource Owner Password Credentials - used with trusted applications
such as those owned by the service itself.
Client Credentials - used with Applications API access.
If I'm developing a mobile application that will consume resources from its own API, i.e., the mobile app is developed by the same team developing the API, which of the four OAuth flows should I use and how?
Given my scenario, it sounds to me like option 3 is the way to go. If this is the case, would you adopt the following process:
Release you mobile app with the ClientId and ClientSecret stored on
it (deemed okay as the application is trusted).
Ask the user to log into their account using cookie-based
authentication (immediately deleting their username and password).
Cache the hash of their username and password returned in the
response of the cookie-based authentication.
Use the cached username and password, along with the ClientId and
ClientSecret, to request access and refresh tokens from the token
endpoint of the OAuth server.
Doe this seem sensible? It would be good to know if I'm on the right track with the above thought process, or if I'm going something incredibly silly and ought to be doing this some other way.
Resource Owner Password Credentials flow would be okay for your case.
BTW, it is difficult for a mobile application to keep its client secret confidential (RFC 6749, 2.1. Client Types, RFC 6749, 9. Native Applications). Therefore, in normal cases, a client secret should not be embedded in a mobile application. In other words, embedding a client secret is almost meaningless in terms of security.
2- Implicit - used with Mobile Apps or Web Applications (applications
that run on the user's device)
If your application runs entirely on a mobile device then you are encouraged to use this flow as your mobile app can't be trusted to keep its client credentials secret.
I trying to implement OAuth 2 provider for web service and then built native application on top of it. Also I want give access to API for third-party developers.
I read OAuth 2 specification already and can't choose right flow. I want authenticate both CLI and GUI apps as well.
First of all we have two client types - public and confidential. Of course both GUI and CLI apps will be public. But what is difference between this two types? In this case for what I need client_secret if I can get access token without it just by changing client type?
I tried to look at some API implementations of popular services like GitHub. But they use HTTP Basic Auth. Not sure it is a good idea.
Is there any particular difference? Does one improve security over the other?
As to the difference between public and confidential clients, see http://tutorials.jenkov.com/oauth2/client-types.html which says:
A confidential client is an application that is capable of keeping a
client password confidential to the world. This client password is
assigned to the client app by the authorization server. This password
is used to identify the client to the authorization server, to avoid
fraud. An example of a confidential client could be a web app, where
no one but the administrator can get access to the server, and see the
client password.
A public client is an application that is not capable of keeping a
client password confidential. For instance, a mobile phone application
or a desktop application that has the client password embedded inside
it. Such an application could get cracked, and this could reveal the
password. The same is true for a JavaScript application running in the
users browser. The user could use a JavaScript debugger to look into
the application, and see the client password.
Confidential clients are more secure than public clients, but you may not always be able to use confidential clients because of constraints on the environment that they run in (c.q. native apps, in-browser clients).
#HansZ 's answer is a good starting point in that it clarifies the difference between a public and private client application: the ability to keep the client secret a secret.
But it doesn't answer the question: what OAuth2 profile should I use for which use cases? To answer this critical question, we need to dig a bit deeper into the issue.
For confidential applications, the client secret is supplied out of band (OOB), typically by configuration (e.g. in a properties file). For browser based and mobile applications, there really isn't any opportunity to perform any configuration and, thus, these are considered public applications.
So far, so good. But I disagree that this makes such apps unable accept or store refresh tokens. In fact, the redirect URI used by SPAs and mobile apps is typically localhost and, thus, 100% equivalent to receiving the tokens directly from the token server in response to a Resource Owner Password Credentials Grant (ROPC) .
Many writers point out, sometimes correctly, that OAuth2 doesn't actually do Authentication. In fact, as stated by the OAuth2 RFC 6749, both the ROPC and Client Credentias (CC) grants are required to perform authentication. See Section 4.3 and Section 4.4.
However, the statement is true for Authorization Code and Implicit grants. But how does authentication actually work for these domains?
Typically, the user enters her username and password into a browser form, which is posted to the authentication server, which sets a cookie for its domain. Sorry, but even in 2019, cookies are the state of the authentication art. Why? Because cookies are how browser applications maintain state. There's nothing wrong with them and browser cookie storage is reasonably secure (domain protected, JS apps can't get at "http only" cookies, secure requires TLS/SSL). Cookies allow login forms to be presented only on the 1st authorization request. After that, the current identity is re-used (until the session has expired).
Ok, then what is different between the above and ROPC? Not much. The difference is where the login form comes from. In an SPA, the app is known to be from the TLS/SSL authenticated server. So this is all-but identical to having the form rendered directly by the server. Either way, you trust the site via TLS/SSL. For a mobile app, the form is known to be from the app developer via the app signature (apps from Google Play, Apple Store, etc. are signed). So, again, there is a trust mechanism similar to TLS/SSL (no better, no worse, depends on the store, CA, trusted root distributions, etc.).
In both scenarios, a token is returned to prevent the application from having to resend the password with every request (which is why HTTP Basic authentication is bad).
In both scenarios, the authentication server MUST be hardened to the onslaught of attacks that any Internet facing login server is subjected. Authorization servers don't have this problem as much, because they delegate authentication. However, OAuth2 password and client_credentials profiles both serve as de facto authentication servers and, thus, really need to be tough.
Why would you prefer ROPC over an HTML form? Non-interactive cases, such as a CLI, are a common use case. Most CLIs can be considered confidential and, thus, should have both a client_id and client_secret. Note, if running on a shared OS instance, you should write your CLI to pull the client secret and password from a file or, at least, the standard input to avoid secrets and passwords from showing up in process listings!
Native apps and SPAs are another good use, imo, because these apps require tokens to pass to REST services. However, if these apps require cookies for authentication as well, then you probably want to use the Authorization Code or Implicit flows and delegate authentication to a regular web login server.
Likewise, if users are not authenticated in the same domain as the resource server, you really need to use Authorization Code or Implicit grant types. It is up to the authorization server how the user must authenticate.
If 2-factor authentication is in use, things get tricky. I haven't crossed this particular bridge yet myself. But I have seen cases, like Attlassian, that can use an API key to allow access to accounts that normally require a 2nd factor beyond the password.
Note, even when you host an HTML login page on the server, you need to take care that it is not wrapped either by an IFRAME in the browser or some Webview component in a native application (which may be able to set hooks to see the username and password you type in, which is how password managers work, btw). But that is another topic falling under "login server hardening", but the answers all involve clients respecting web security conventions and, thus, a certain level of trust in applications.
A couple final thoughts:
If a refresh token is securely delivered to the application, via any flow type, it can be safely stored in the browser/native local storage. Browsers and mobile devices protect this storage reasonably well. It is, of course, less secure than storing refresh tokens only in memory. So maybe not for banking applications ... But a great many apps have very long lived sessions (weeks) and this is how it's done.
Do not use client secrets for public apps. It will only give you a false sense of security. Client secrets are appropriate only when a secure OOB mechanism exists to deliver the secret and it is stored securely (e.g. locked down OS permissions).
This is more of a general question but I hope it is still valid for SO.
So far I have learned, that in general, a mobile app (such as official Pinterest app) use the Password credential flow to let their users login and access the API directly. (let's just assume they use OAuth for this)
So they collect username and password, send it to their server and get a token in return which is used for subsequent requests.
Now a user did not want to register and created an account using e.g. Facebook as the authorization server. So my question is:
How is this flow implemented?
My educated guess:
User chooses "Login with Facebook" in mobile app
Facebook Login Page opens with return_uri = mobile app
Mobile app receives auth token
Mobile app uses client credentials and says the API: Use this token for user X
Is this correct?
First of all, apps should not use the Password Credentials Grant. The specification is rather clear about it:
In the traditional client-server authentication model, the client
requests an access-restricted resource (protected resource) on the
server by authenticating with the server using the resource owner's
credentials. In order to provide third-party applications access to
restricted resources, the resource owner shares its credentials with
the third party. This creates several problems and limitations
The specification then goes on describing those problems.
And about the Resource Owner Password Credentials Grant:
The authorization server should take special care when enabling this grant type and only allow it when other flows are not viable.
The entire purpose of OAuth 2.0, I to not have to use something like the Password Credentials Grant, where the user hands over their password to the application.
About your second question: what happens when a user does not want to register and create an account with your app, but wants to use e.g. Facebook for authentication?
Remember that both the Implicit Grant, as well as the Authorization Code Grant, work by using a browser control to authenticate the user. In that browser session with the Authorization Server, you are free to authenticate your user in any which way you want. Certainly, you can use your own user/password database, but you could also use other mechanisms, such as WS-Federation. In your case, it sounds like the user want to authenticate using Facebook.
Authenticating using Facebook is then not done by your client app, but by your Authorization Server. It typically does that by using the Facebook Authorization Code Grant, followed by a call to read the user's profile to obtain their Facebook user id, name, and so on.
If you do not want to build such an Authorization server yourself, you can use an existing one. Several companies offer login-as-a-service solutions, including the one I work for.
UPDATE: You asked several follow up questions in a comment below. I'll answer them briefly here:
First of all, the fact that some companies that use OAuth to secure their services allow for a Password Credentials Grant, does not imply that you should. In fact, there are probably more examples of companies that don't offer this possibility, than companies that do.
There are real trust issues, and real security risks with sharing your password with a device app. To start with, the app on the device is easier to hack than a server. Furthermore, if you give the app your password, presumably that app also needs to store it somewhere for future use. As a user, I just have to hope that that storage is safe form possible malware running on my machine. For more issues, see the introduction in the OAuth 2.0 specification mentioned above.
Secondly, all good Authorization Servers differentiate between First Party Clients and Third Party Clients. A First Party Client such as yours is controlled by the same company that controls the Authorization Server, and for such an app the Authorization Server does not ask for user permission to share data, since it makes no sense to talk about sharing data with yourself. That is why the web sites of these companies don't ask you whether you allow to share the data they hold on your behalf with them. They already have it, and there is no "sharing" going on.
Of course, you might argue that you have never seen any of these companies talking about this distinction between First Party Clients and Third Party Clients. But the reason they don't should be obvious: when you deal with them, you are always a Third Party App. They don't need to tell you that they treat themselves differently.
The mechanism I would choose in your scenario depends on the nature of the client app, and the nature of the services it accesses. What are your requirements?
Anyway, if the device the application is running on has a secure storage facility, such as Windows Phone 8.1, I would probably consider using the Authorization Code Grant without client credentials. That way, the user never has to log in again. If we're talking about a web site or a SPA, I would consider the Implicit Grant (where the "remember me" feature, if any, is offered by the Authorization Server). Again, the specification gives advantages and disadvantages of each grant type for several scenario's.
Is it possible to make oauth secure on iOS?
I am investigating OAuth 2.0 as a means to implement single sign-on + authorization for a "suite" of iOS apps. To explain my concerns, I'll simplify and use Facebook + a 3rd party app that uses Facebook for authentication (let's say Words/"Words with Friends").
For the purpose of example, I'll assume that Facebook registers to support scheme/protocol "facebook://" and that Words registers to support "words://"
I also make the assumption that it is not possible to secure the "client-secret" or the protocol in an iOS application because you can decompile the application. Any ways that I have come up with to secure this results in security by obscurity.
Another assumption is that there is no way to prevent two applications from registering to handle the same protocol. The behavior when two apps both register for the same protocol is indeterminate. (Although it appears that the first app to launch on the device gets registered while the second apps registration is ignored)
If I understand the workflow between Facebook (user-agent) and Words (client) on the iOS device:
User launches Words
user chooses to logon via Facebook credentials
Words invokes openUrl("facebook://") which contains, among other things an identifier for Words as an application and a redirect uri (i.e. "words://")
iOS launches Facebook application
User enteres credentials, which Facebook application validates against Facebook authorization server.
User prompted to authorize Words to access Facebook data (i.e. Words can access my friends list)
Facebook invokes callback uri provided by Words along with access token (i.e. words://access_token?token_here)
Words uses this token to access my friends list (i.e. protected resource data)
Assuming the above is correct, if I want to be malicious and access random people's friends list, I could create an application that also registers to handle the protocol "words://" and get it on the app store. If someone has my app and Words installed and my app is the one that successfully registered (i.e. launched on the device before Words), then:
Launch Words, choose to logon, launches Facebook
user authenticates / authorizes
Facebook attempts to redirect back to Words by invoking openUrl on the redirect url
My App (not Words) is launched
My App now has access to the auth code, which (with the secret learned by decompiling) can be exchanged for an access_token, with rights to access your friends list
I am hoping that my reasoning is flawed above or I would have to conclude (specifically) that Facebook iOS authentication for 3rd party apps is insecure.
More generically, is it possible to implement OAuth 2.0 (authorization/implicit grant workflows) securely on iOS application?
Google has come up with an experimental solution for this problem that they call OAuth 2.0 for Installed Applications.
The Google OAuth 2.0 endpoint supports applications that are installed on a device...it is assumed that these applications cannot keep secrets.
Essentially, the shared secret is treated as non-secret.
At the time of this writing, most OAuth 2.0 servers do not seem to support this experimental design.
This design introduces the risk that an attacker could create a new client that represents itself as your application to the authorization server (the attacker would need to obtain the client identifier as you describe in your question, or by following one of the techniques suggested here).
However, this risk seems to be mitigated by the fact that the resource owner (the user) would be unlikely to authorize the malicious application to take any action on protected resources, since he/she will know that the application is not, in fact, your application.