How to store OAuth client id on native apps - oauth-2.0

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

Related

Oauth pkce flow impersonating someone else's client

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.

How to prevent non-approved 3rd Party SPA access to resource when using OAuth 2.0 for authorisation?

I'm trying to allow access to our publicly facing APIs to approved Single Page Applications only.
We currently use OAuth 2.0 to control access to our APIs. The high level scenario is that our users will access our publicly available SPA, provide their username and password, and then be able to use the SPA which in turn will be able to use our APIs.
The current best practice for OAuth 2.0 with SPA is to use the authorisation code grant with a client id but without the client secret, as obviously an SPA cannot keep any secrets.
My question is how can we prevent a third party SPA from accessing our APIs. I.e. they could extract the existing client_id from our SPA and request an authorisation code in the same way as our first party SPA. Assuming they can persuade a user to login they can then access our APIs.
Is the pre-registered redirect URL the only defence in this scenario? If so, does that mean that if we switch to using the resource owner credentials grant for a better user experience (not recommended I know) there would be no protection from third party apps at all?
I've read the various RFCs for OAuth and this page in particular is very useful but doesn't quite answer my question:
https://auth0.com/blog/oauth2-implicit-grant-and-spa/
Indeed the pre-registered Redirect URI is the only defense mechanism in this case of a public Client when using the so-called Implicit grant type. An attacker may trick the user in starting the flow but will not receive the issued token on a Redirect URL that it controls. This is similar to tricking the user into starting any other login flow.
Since the attacker does not obtain a token (it is still delivered on the intended Redirect URI controlled by the Client) he cannot access your APIs, even if he can persuade the user to login.
When the attacker controls DNS things become more dangerous but that goes for a lot of things outside of OAuth 2.0 as well. In general: delivering tokens to an in-browser app is going to suffer from this type of vulnerability regardless of the protocol used.
Switching to Resource Owner Password Credentials has a lot of drawbacks, including one where the attacker can present an app similar to yours to obtain the username/password (which also block you from upgrading to multi-factor authentication as the other grant types would allow you to).
In summary: there is protection against it although not super strong.
FWIW: the latest OAuth 2.0 best practices suggest that tokens should no longer be directly delivered to the Redirect URI but use an intermediate short-loved one-time usage Authorization Code instead to allow the SPA to get its tokens in an XHR call directly from the token endpoint.

Best practice for OAuth Tokens for a combination of native apps and backend processes

I have a scenario in which a mobile (native) app is requiring data from a long running task. The task is a continuesly running on the users behalf, and we have decided to move it to a backend service. To execute the task, the backend service must regularly fetch data from an API that is OAuth2 protected.
Our dilemma is that we are not sure how to provide the backend service with a set of access tokens to access the data API. Our mobile app uses the OAuth2 Authorization Grant flow with PKCS to get its own access token, refresh token and id-token (we use OpenID Connect). But how do we provide our backend service with a set of tokens? As the backend is continuesly running (also in absence of the mobile native app) we would like to provide it with its own set of access/refresh tokens.
There seem to be several solutions:
Proxy all mobile app communication to external APIs via the backend, make the client a private client, use the authorization code flow, and setup custom login sessions between the native app and our backend. To me this means more running backend infrastructure, and implementing session management including session refresh, etc. which is like re-implementing the OpenId flows on my own servers...
Using OpenID hybrid flow, providing both an access token as well as an authorization code to be shared with the backend. However, this seems to be directed at (in-browser) web-apps, not so much native mobile apps as it based on the implicit flow and as such less secure.
Doing the authorization code flow twice on the mobile app (optionally second time with prompt=none to suppress user interaction), keeping one code for the app, forwarding the second to the backend. Then both backend and app can exchange their own codes for access tokens. This feels a bit like a hack as the backend should be a private client, not a public client. It is the approach that Google seems to advertise though in CrossClientAuth
Performing impersonation by sending the id-token to the backend which then exchanges that id-token for its own set of access/refresh tokens. Microsoft does this through the jwt-bearer grant in its "on-behalf-of" scenarios. Moreover, the token-exchange RFC seems to cover the same use-case. However, in this scenario the id-token is indirectly used as access credential, not just as a bag of claims about the user identity, which is odd in my view as access should be controlled through access tokens, is it not? Moreover, not all services should be allowed to impersonate, so I suppose this comes with additional configuration complexity.
To me it feels that I'm overlooking something, this must be a problem others have too and must have been solved before... What would be best practice in my situation?

oauth2 openid connect javascript (electron) desktop application

What is the correct oauth2 flow for a desktop application? Besides a desktop application I have a SPA Web GUI which does use the Implicit flow. There it does not matters if the client Redirects after 3600s to the IdP to issue a new Access token.
But the desktop application needs to be running 24/7 or could be running 24/7. So it needs to automatically refresh the access token via a refresh_token. But since the implicit flow does not provide refresh tokens it is probably the wrong flow for a desktop app, isn't it?
I guess I need the auth code flow, which does provide a refresh_token. But authentication requests needs a redirect_uri. Let's say I want to use Google as my openid provider. With google it looks like I can't register client credentials with a custom URI scheme (https://developers.google.com/identity/protocols/OpenIDConnect). What does work is to register for example http://localhost:9300, which theoretically could be handled by the app.
A
Whats the correct oauth2 flow for a desktop app to receive a refresh_token?
B
Can I catch the redirect_uri via a custom URI scheme without using the implicit flow (Google IdP)? It is way easier to listen for a custom uri scheme than listening on a local tcp port.
C
This is more a general question. Usually desktop apps are public apps, so I should not include client_secret right? So the only flow which would be left is the implicit flow. But how can I renew access tokens according to specs without bother the desktop user every 3600s?
In my case I could publish the app locally so not public, but how is it for a public app?
A - Authorization Code Grant
B - Not sure here, You can register a Custom URI Scheme
C - Not enough information provided.
Are you using the AppAuth libraries? If so you SHOULD use PKCE and then additional security measures for the refresh token should not be necessary, on the assumption that the client never sends the refresh token with anyone other than the IDP over a secure connection.
Does this help?
A: Yes use the code grant
B: yes use a custom scheme. In your case you should use the reverse of your client ID. e.g. com.googleusercontent.apps.123 is the reverse DNS notation of the client ID. Register your client as "Other" in the Google developer console.
C: Yes, it should not include the client secret. That is why you don't need to send the secret for native clients ("Other") when exchanging the code for a refresh token. Just leave that field blank and it'll work.
As suggested by jwilleke, please use an AppAuth library if it is available for your use case as it'll also handle some of the security issues (PKCE).
For native apps (Desktop), you can follow OAuth 2.0 for Native Apps. But this is still under review and you can refer the latest draft from provided link.
With this flow, you can use authorisation code flow to obtain both access token and a refresh token. Refresh tokens should solve the UX related issue when it comes to extended app usage (24/7 and beyond).
According to this working document, there are strict guidelines on client authentication. Section 8.5 discuss about them. As it says client credentials are not recommended
For this
reason, and those stated in Section 5.3.1 of [RFC6819], it is NOT
RECOMMENDED for authorization servers to require client
authentication of public native apps clients using a shared secret
Also as nvnagr has mentioned in his answer, PKCE [RFC7636] is a must to have for native public clients.

Can I use Oauth2 Authorization Code flow for a SPA (React app), if I have a server-side proxy?

After watching an obscene amount of tutorials on OAuth2, there is one best practice that everyone repeatedly states - if you have a React app (or Angular, or Ember) - you must use Implicit flow with it.
I understand that storing client credentials in publicly visible javascript would not work. However, my scenario is a bit different:
I'm only using Oauth2 for single sign on and token generation for microservices. I chose it instead of simply generating tokens, since well-supported third party libraries are built around the Oauth2 idea.
My idea is to have a React app, and a ASP.NET MVC app which serves the javascript and acts as a proxy for API requests. The user authenticates for the server-side app (by using Oauth2 authorization code flow).
Then if I need to retrieve data from an API, I call my ASP.NET MVC app from React (by sending a simple cookie). The MVC app holds the token without ever exposing it to the user's browser.
Obviously, when called, my MVC app then redirects the request to the necessary API, providing the bearer token.
To better understand why this is what I came up with, here are some requirements I've received that might be unusual:
I really don't want the access token to be shared - even if it's relatively short lived.
I also want to be able to limit each user account to 3 concurrent user sessions. Easy to do using cookies and server-side sessions.
I can't wrap my head around why this idea would be that bad. Is there any technical problem that might prevent this from working? Or maybe a security risk?
The authorization code flow returns an authorization code (like it says on the tin) that can then be exchanged for an ID token and access token. This requires client authentication using a client id and secret to retrieve the tokens from the back end and has the benefit of not exposing tokens to the User Agent.
This flow allows for long lived access (through the use of refresh tokens).
Clients using this flow must be able to maintain a secret.
Accordingly to your description, you have service-to-service authorization flow, and as your service are not exposing client secret key it is totally OK to use the Code flow. Moreover, you should use it to allow long lived tokens.

Resources