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.
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
I'm trying to use KeyCloak as identity provider service for 3rd party applications support. The idea is to register the client application in KeyCloak, trusted clients will not require this authorization approval, but there should be "untrusted" client flow, e.g. display user authorization interface as specified in OAuth 2.0 specification.
From what I see in the docs, they have pretty good fine-grained authorization mechanisms which can be used for that on the backend. However I don't see any way to provide authorization screen for /authorize endpoint as shown above.
Maybe this can be custom created SPI or something else which can be used for implementing this to move further. Any ideas of how this can be implemented in KeyCloak? Are there any built-in features which can be reused or custom way implementation?
In Keycloak you can turn on the Consent Required switch per client (see client settings in admin console).
After successful authentication this will bring up a confirmation page similar to your example.
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.
You can implement the "Authorization Code Flow" in this situation?
A single page app in www.app.com
A REST backend in www.backend.com
Is possible to obtain via javascript an "authorization code" and then pass it to the "backend" for this get the "access token"?
In theory, using the authorization code flow (or the hybrid flow) with a JS/mobile/desktop application is definitely possible, and you don't even need to store client credentials for that (you could, of course, but extracting them is so easy that it would be pointless).
Contrary to popular belief, client authentication is not required for "public" applications (i.e apps that cannot safely store their credentials, which includes JS apps) when using the authorization code flow:
If the client type is confidential or the client was issued client
credentials (or assigned other authentication requirements), the
client MUST authenticate with the authorization server as described
in Section 3.2.1.
https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3
f the Client is a Confidential Client, then it MUST authenticate to the Token Endpoint using the authentication method registered for its client_id, as described in Section 9.
http://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
In practice, I'm pretty sure most authorization/authentication servers will enforce client authentication when using the authorization code flow and will instead recommend using the implicit flow for public apps.
If your authorization server supports this scenario, using the authorization code flow in your JS app should be easy if you use response_mode=query (or better: response_mode=fragment as suggested by #Hans), since you can use your JS main page as the redirect_uri and use some JS to extract the authorization code from the query string or from the fragment.
That is possible by setting the redirect_uri to somewhere in your SPA, pickup the code from the authorization response (using any of the methods described in How to get the value from the GET parameters?) and pass it on to the backend in an application specific way. When using OpenID Connect there's the option to have the code delivered in the fragment of the redirect_uri which has some security advantages over having it delivered as a query parameter.
It's funny but I can't find description of using HTTP requests to receive Google+ authentication code for offline access without iOS Google+ library.
Though example of it's integration is pretty straightforward, I don't want to add additional 20mb of weight to my iOS app.
I tried the approach described here
https://developers.google.com/accounts/docs/OAuth2WebServer#offline
but in case of server clientId I receive message abount incorrect redirect uri.
Could someone give me advice about it?
There are two approaches you could take that may/may not work for you.
Installed app flow with internally stored client secret
Web flow within a web view.
Installed app flow
You will must likely need to use the offline OAuth v2 / installed app flow which has redirect URI that has something like urn:ietf:wg:oauth:2.0:oob enabling you to redirect back to the browser, from there you can get a code to exchange for tokens.
In your case, I'm guessing you didn't create the right client type (installed application) which is preventing the *:oob redirect.
It's less secure to handle sign in in this way - if the user can extract the client secret from your app, they can do bad things like authorize a malicious 3P app with access to your application data.
Web signin flow
An alternative would be to use the web signin flow from within a WebView, something that Apple may reject your app for and which is also insecure.
What you would do is host the sign-in solution on your web server, use the JavaScript web signin flow to initiate sign in, request offline access, then exchange the resulting code for an access token and refresh token.
You would then store the refresh token / access token on the device and exchange it for an access token when you need access to the user data or exchange the refresh token server-side and pass the bearer token back to the iOS app when it needs access. This again is bad because it can expose other apps to user authorization credentials and could potentially allow a malicious 3P to access user data.
I can't recommend either approach. Is there a reason other than the app size impact that you can't use the library? I'll see if there is a good way to avoid the file size hit from the framework.