cross client identity and iOS - ios

Does Google currently support cross client/platform auth for iOS? We need both our server and iOS app to be authorized to hit Google endpoints.
Instructions described in https://developers.google.com/accounts/docs/CrossClientAuth don't really work for iOS.
The only workaround I can think is have the iOS app do the initial user auth and pass the code + refresh token to the server and moving forward the server shares the access token with the app whenever the access token expires.

Need more info about your use case to make a recommendation, but I have found it's easier to drive the initial auth/access-code/refresh-token stuff from the server, and then let the client app request access tokens as required.
To answer your specific question, cross client auth is supported for iOS, but iOS lacks some of the convenience mechanisms which apply to the initial auth process.

Related

How to give access to my api for a mobile app?

i have to develop the backend of a mobile app (IOS swift). I started to create the api with laravel.
But i'm concerned about the access to my api: how i should i give access to my api ? i've heard some stuff about Oauth key and passport .
For my app i want to :
-user can create an account (i guess it's with JWT)
-user can navigate in my app and start to use it after they create their account.
I wan't know the basic process about creating an api for a private use (only my app will use it) what security stuff should i implement and how the account creation for my app will work. Thx :)
PRIVATE APIs
wan't know the basic process about creating an api for a private use (only my app will use it)
Let me tell you here a cruel truth...
No matter if an API doesn't have public accessible documentation or if is is protected by any kind of secret or authentication mechanisms, once is accessible from the internet is not private any-more.
So you can make it hard to find and access, but to truly lock it to your mobile app you will gonna have an hard time to do it so.
WHO AND WHAT IS ACCESSING THE API SERVER
The WHO is the user of the mobile app that you can authenticate,authorize and identify in several ways, like using OpenID or OAUTH2 flows.
Now you need a way to identify WHAT is calling your API server and here things become more tricky than most developers may think. The WHAT is the thing making the request to the API server, is it really your genuine mobile app or is a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
Well to identify the WHAT developers tend to resort to an API key that usually they hard-code in the code of their mobile app and some go the extra mile and compute it at run-time in the mobile app, thus becomes a dynamic secret in opposition to the former approach that is a static secret embedded in the code.
REVERSE ENGINEERING A MOBILE APP BINARY IS EASY
The truth is that anything running in the client side can be reverse engineered
easily by an attacker on a device he controls. He will use introspection frameworks like Frida or xPosed to intercept at runtime the running code of the mobile app or will use a proxy tool like MiTM Proxy for watching the communications between the mobile app and the API server. Normally their first step in reverse engineer a mobile app will be to use the Mobile Security Framework to reverse engineer the binary of you mobile app to extract all static secrets and to identify attack vectors.
Mobile Security Framework
Mobile Security Framework is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing framework capable of performing static analysis, dynamic analysis, malware analysis and web API testing.
Frida
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
xPosed
Xposed is a framework for modules that can change the behavior of the system and apps without touching any APKs. That's great because it means that modules can work for different versions and even ROMs without any changes (as long as the original code was not changed too much). It's also easy to undo.
MiTM Proxy
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
So now what... Am I doomed to the point I cannot protect my API server from being abused??? No quiet so... hope still exists!!!
A POSSIBLE SOLUTION
So anything that runs on the client side and needs some secret to access an API can be abused in different ways and you can learn more on this series of articles about Mobile API Security Techniques. This articles will teach you how API Keys, User Access Tokens, HMAC and TLS Pinning can be used to protect the API and how they can be bypassed.
But i'm concerned about the access to my api: how i should i give access to my api ? i've heard some stuff about Oauth key and passport .
For my app i want to :
-user can create an account (i guess it's with JWT)
-user can navigate in my app and start to use it after they create their account.
...and how the account creation for my app will work.
Laravel Passport is an OAUTH2 server thus is a good solution to use for user creation and identification, thus to solve the problem of WHO is using your mobile app and API server.
what security stuff should i implement
To solve the problem of WHAT is accessing your mobile app you need to use one or all the solutions mentioned in the series of articles about Mobile API Security Techniques that I mentioned above and accepted that they can only make unauthorized access to your API server harder to bypass but not impossible.
A better solution can be employed by using a Mobile App Attestation solution that will enable the API server to know is receiving only requests from a genuine mobile app.
Mobile App Attestation
Use a Mobile App Attestation solution to enable the API server to know WHAT is sending the requests, thus enabling it to only respond to requests from a genuine mobile app.
The role of a Mobile App Attestation service is to guarantee at run-time that your mobile app was not tampered or is not running in a rooted device by running a SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device is running on.
On successful attestation of the mobile app integrity a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud are aware. In the case of failure on the mobile app attestation the JWT token is signed with a secret that the API server does not know.
Now the App must sent with every API call the JWT token in the headers of the request. This will allow the API server to only serve requests when it can verify the signature and expiration time in the JWT token and refuse them when it fails the verification.
Once the secret used by the Mobile App Attestation service is not known by the mobile app, is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.
The Mobile App Attestation service already exists as a SAAS solution at Approov(I work here) that provides SDKs for several platforms, including iOS, Android, React Native and others. The integration will also need a small check in the API server code to verify the JWT token issued by the cloud service. This check is necessary for the API server to be able to decide what requests to serve and what ones to deny.

Native Android / Google login with Azure AppService

Not sure if that is possible: I would like to switch from server flow to native client flow in order to provide a better authentication experience for my users.
The problem is that Azure AppService requires a "web application" OAUTH setup (contains client ID and a secret), while the native login works with just a client ID and not secret. This means that after the login on the phone, I do have a Google token, but AppService wouldn't know what to do with it and returns me an HTTP Unauthorized.
The mobile client SDK gives me an API, but that doesn't work with such a token.
var jObject = new JObject(
new JProperty("access_token", auth.AccessToken),
new JProperty("id_token", auth.IdToken));
await ServiceClient.LoginAsync(MobileServiceAuthenticationProvider.Google, jObject);
Any idea on the proper way to integrate this without having to write my own server-side token validation?
You would still need to configure the web application in Google since you are attempting to access a non-Google API. The native login on its own is not enough.
That means you will still need to provide the backend with an ID and secret. The client is responsible for obtaining an id token and authorization code which get sent to the server, and the server does the actual retrieval of the access token, per the Google documentation.
So that means your call will actually look something like the following:
var jObject = new JObject(
new JProperty("authorization_code", auth.ServerAuthCode), // not sure what property your auth binding exposes this as
new JProperty("id_token", auth.IdToken));
await ServiceClient.LoginAsync(MobileServiceAuthenticationProvider.Google, jObject);
There isn't documentation for the end-to-end using Xamarin.Android, but you might find it useful to glance over the App Service iOS documentation for this scenario just to see the moving parts. The general pattern you will follow is:
Configure everything for the server flow (as you've done before)
Set up the Google Sign-in SDK (seems like you've done that already, too).
Make the call as described above
The main issue you might run into is making sure that you have the API console registration correct. You'll want to make sure you have an Android client there connected to the web application client ID you are using. I'd recommend giving the Google Sign-in for Android setup instructions a quick look. Also note that authorization codes are one-time use, and there are some throttles that Google puts in place for a user requesting too many of them within some span of time. You might run into that during dev.
AS far as I know, the native client flow also use the google code flow to get access token.
According to this article, the Android, iOS, or Chrome applications doesn't need the secret to get the access token.
The client secret obtained from the API Console. This value is not needed for clients registered as Android, iOS, or Chrome applications.
But the web app backend will not authorized this access token if you don't set in your backend to enable Azure App Service authentication/authorization. Because the backend will have its own logic(the mobile server library write the logic according to the access token) to return the auth token according to the access token.
Now, the most easily way to enable the client flow in your mobile app is set in your backend to enable Azure App Service google authentication/authorization with the same clientid and secret(based on my test: if you don't set the right secret, the backend will still return the auth token).
Here is the test image:
If you still don't want to enable the app google easy auth, I suggest you could create custom authentication which contains your own logic to check the accesstoekn and get the user information from the google.
If the checked result is success and get the enough value, you could generate the auth token and return to the client side.
More details about how to create custom authentication in the mobile app backend , you could refer to this article.

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.

Cross-client Google OAuth: Get auth code on iOS and access token on server

I'm trying to set up Google OAuth with my iOS app and Rails web app. I have 2 separate clients (with of course different client IDs, but with the same prefix) set up in the API Console. One for the iOS app, and the other for the web app (which also has a client_secret. I want to use the AppAuth SDK on iOS to get the user's auth code, then send that to my web app, which will then perform the exchange for the access token.
First of all, does this sound like a reasonable thing to do, or is it not possible to split the transaction across clients like that?
My first try was to just take the auth code and perform the exchange, but that failed with the missing_code_verifier invalid_grant error, so I also passed the same code_verifier that AppAuth used to get the auth code to my server, and that fixed that error. First of all, is it necessary to pass this code verifier to the server? Seems a little strange.
Now though, it fails with the unauthorized_client error. My web app is making a request like this:
{
"grant_type"=>"authorization_code",
"code"=>"4/XYZ...",
"client_id"=>"WEB_APP_CLIENT_ID_HERE.apps.googleusercontent.com",
"client_secret"=>"WEB_APP_CLIENT_SECRET_HERE",
"redirect_uri"=>"https://www.myapp.com/oauth_callback",
"parse"=>"json",
"code_verifier"=>"CODE_VERIFIER_STRING_HERE"
}
Looking at posts like:
Unable to exchange authorization code for access token and refresh token in Cross Client google oauth2.0
Google+ Sign-in for server-side apps, exchanging auth code for access token
it looks like the redirect_uri might be an issue here. My AppAuth config on iOS has the redirect URI set as com.googleusercontent.apps.iOS_CLIENT_ID_HERE, and the Info.plist URL scheme too. The web app's "Authorized redirect URIs" section in the API Console has a bunch of web URLs, and I added the com.google... to it as well. Is this config incorrect? Is the redirect_uri important when doing cross-client auth?
Any help is greatly appreciated! All my trial-and-error have had no fruition so far :(
I am the lead maintainer of AppAuth, and work on the Google Identity Platform; hopefully I can help.
I want to use the AppAuth SDK on iOS to get the user's auth code, then send that to my web app, which will then perform the exchange for the access token.
First of all, does this sound like a reasonable thing to do, or is it not possible to split the transaction across clients like that?
Exchanging the code on your server sounds reasonable, however I think the configuration you are using is possibly incorrect. If you are requesting a code for exchange on your server, use the server's client id in the request to the authorization server. From your description it sounds like your authorization server request is sending your iOS client ID, and you are then doing the exchange with your server client ID, and I believe this is why you are seeing an "unauthorized_client" error.
This is not terribly well documented, apologies for that. It is alluded to in this section of the documentation on "offline access", though it talks about it purely in terms of Android usage via GoogleApiClient.
is it necessary to pass this code verifier to the server? Seems a little strange.
The intention behind PKCE is to ensure that the entity making the authorization request is the same as the entity making the code exchange request. The code_verifier should not leave the device under normal circumstances.
However, it is not necessary to use PKCE if you are exchanging your code using a client secret controlled by your backend; you can disable PKCE in AppAuth for this scenario.

Receive cross-client Google+ authorization code for offline access without library on iOS

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.

Resources