54

I am trying to authorise a user for Google calendar API inside an IOS app. I am using the OAuth2 feature of Google to authenticate users. Authorisation page opens with a 403 error with the description:

This user-agent is not permitted to make OAuth authorisation request to Google as it is classified as an embedded user-agent (also known as a web-view). Per our policy, only browsers are permitted to make authorisation requests to Google. We offer several libraries and samples for native apps to perform authorisation request in browser.

I followed the same procedure which is mentioned in this link: https://developers.google.com/google-apps/calendar/quickstart/ios

Rather than seeing my code, it's better to look at this link: https://developers.google.com/google-apps/calendar/quickstart/ios because I copy-pasted the same thing in my application.

below are my clientId and keyChainItemName:

static NSString *const kKeychainItemName = @"Google Calendar API";
static NSString *const kClientID = @"954370342601-sgl8k0jrbqdeagea9v6vfu3tspte96ci.apps.googleusercontent.com";
TylerH
  • 20,799
  • 66
  • 75
  • 101
Subbu
  • 541
  • 1
  • 4
  • 5
  • Show your source code – Alexander Farber Nov 14 '16 at 14:35
  • What approach did you go with? – Bhumit Mehta Jan 04 '17 at 14:41
  • @Subbhu Did you get any solution for this? – Alok Jan 11 '17 at 10:11
  • 3
    I faced this error in Android. I solved by setting "User Agent" for local WebView settings i.e. String ua = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0"; webview.getSettings().setUserAgentString(ua); You can find more in respect of IOS here: https://forums.xamarin.com/discussion/86415/google-auth-error-disallowed-useragent – Kalu Khan Luhar May 11 '17 at 05:46
  • 2
    this policy sucks, we have an established webview based OAuth approach (multi-platform with server side control) for various third party apps. And we're supposed to put in some special browser flow for Google apps? Using a webview allows us to do certificate pinning with our server communication + it gives us more control to strip sensitive info from headers + we need to facilitate login to multiple accounts for the same third party app (not all third party APIs allow you to force prompt to login and so sometimes it is essential to clear the cookies using webview approach). – hmac Sep 26 '17 at 09:19

15 Answers15

36

In my case I was using native web view to login with Google, I find out the way that you should provide user agent to webview it was worked for me. Try below code I am sure it will worked.

Add the code in application didFinishLaunchingWithOptions

Objective C

 NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:@"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36", @"UserAgent", nil];
 [[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

Swift

UserDefaults.standard.register(defaults: ["UserAgent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"])
Tulleb
  • 8,919
  • 8
  • 27
  • 55
Dipen Chudasama
  • 3,063
  • 21
  • 42
  • 2
    Just to clarify the Objective C solution. Add this code to: (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {} – itzo Nov 20 '17 at 20:56
  • Still gives out the same error. Anyone else who is still facing the same? – Rishi Raj Aug 30 '19 at 19:21
  • 1
    Worked well for me. You can use newer UserAgent by finding one here https://developers.whatismybrowser.com/useragents/explore/software_name/safari/?order_by=-software_version and c/p string – Babac Nov 13 '19 at 16:04
17
<preference name="OverrideUserAgent" value="Mozilla/5.0 Google" />

I also face this issue on my cordova project. You can try this: Just add this to your config.xml, worked for me.

Brian White
  • 8,332
  • 2
  • 43
  • 67
Hardeep Singh
  • 818
  • 9
  • 14
16

The short answer is that Google has updated its security restrictions for OAuth flow. They are not going to allow native web-views to initiate OAuth flows, but rather are encouraging people to use the OS browsers to do so. In your case, you'll probably have to wait for the Google calendar SDK to update their code to obey the newly recommended flow. More information is available in the Google blog

EDIT : I have tried to create a cross platform plugin which wraps around the native Google sign-in SDKs for using in a Xamarin forms app. More information can be found here

Rhishikeshj
  • 302
  • 2
  • 9
  • Thanks a lot @Rhishkeshj but it does not give solution for this issue. I want to know any other alternatives available.. still i am seeking for Answers – Subbu Nov 15 '16 at 12:29
  • Issue was logged for drive as well https://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=4919 – Linda Lawton - DaImTo Nov 17 '16 at 12:21
  • @Subbu Unfortunately there is no easy solution around this right now. The thing that I did was to use the native Google sign in SDKs and integrate them separately into the iOS and Droid projects. Seems to be working fairly well, although the usage from a PCL is currently very limited for that. I am trying to develop this setup into a standalone plugin. So lets see. – Rhishikeshj Dec 05 '16 at 06:38
  • Incredibly, this problem also happens with the native browsers from Android 4.x from the pre-Chrome monopoly and updateable webview-era. – andreszs May 04 '17 at 02:57
12

Got same issue. Resolved by setting following property to the webview object:

webview.getSettings().setUserAgentString("Chrome/56.0.0.0 Mobile");

Hope this will help.

Christian Ascone
  • 1,117
  • 8
  • 14
8

As mentioned in previous answers, SFSafariViewController is a way to go, but for those who still uses WKWebView for OAuth authorization there is a simple workaround.

Just change customUserAgent to either one from list or set it to some arbitrary value. After that disallowed_useragent error will disappear:

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
// Check for selector availability, as it is available only on iOS 9+
if ([webView respondsToSelector:@selector(setCustomUserAgent:)]) {
    webView.customUserAgent = @"MyCustomUserAgent";
}

For changing User-Agent in UIWebView you can check this answer.

But be careful, as some backend code can depend on User-Agent header value.

Community
  • 1
  • 1
Maxim Pavlov
  • 2,962
  • 1
  • 23
  • 33
3

By default, if you don't have any google app, the google SDK opens the login inside a UIWebView when we initiate the login by using the following method.

        [[GIDSignIn sharedInstance] signIn];

I just added one line before this, which is as follows.

        [[GIDSignIn sharedInstance] setAllowsSignInWithWebView:NO];

Now the google doesn't authorise using the UIWebView popup. Instead, it opens in the Safari browser. And now everything just works as the way it was.

Ramaraj T
  • 5,184
  • 4
  • 35
  • 68
3

Google decided to not longer allow embedded browsers to handle the oAuth authentication. The best way is to use SFSafariViewController on iOS. Here is how it can be solved using the CloudRail SDK:

In Objective-C:

@implementation AppDelegate

  // This method will receive the redirect URI after the authentication process was
  // successfull
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {

  // Here we pass the response to the SDK which will automatically
  // complete the authentication process.
  [[NSNotificationCenter defaultCenter] postNotificationName:@"kCloseSafariViewControllerNotification" object:url];

  return YES;
}

@end

and Swift:

// This method will receive the redirect URI after the authentication process was
// successfull
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {

    if (sourceApplication == "com.apple.SafariViewService") {
        // Here we pass the response to the SDK which will automatically
        // complete the authentication process.
        NSNotificationCenter.defaultCenter().postNotificationName("kCloseSafariViewControllerNotification", object: url)
        return true
    }
    return true
}

The complete blog post covering this issue can be found here: Solving ‘disallowed_useragent’ for Google services

Tmm
  • 187
  • 4
2

Take a look at this issue. Use GTMAppAuth instead.

Sally
  • 296
  • 3
  • 4
2

There is a workaround for this issue after the recent change in Google OAuth policies.

After integrating the Google Sign and enabling Google Calendar API, I was able to work with Google Calendar API to fetch and add Calendar Events. We just have to set the authorizer for GTLServiceCalendar which is obtained after Google sign-in.

service.authorizer = user.authentication.fetcherAuthorizer()

Here is the code snippets of Google GIDSignIn, followed by fetching calendar events.

import GoogleAPIClient
import GTMOAuth2
import UIKit
import GoogleSignIn

class ViewController: UIViewController, GIDSignInUIDelegate, GIDSignInDelegate {

  private let kApiKey = "AIzaXXXXXXXXXXXXXXXXXXXXXXX"

  // If modifying these scopes, delete your previously saved credentials by
  // resetting the iOS simulator or uninstall the app.
  private let scopes = [kGTLAuthScopeCalendar]
  private let service = GTLServiceCalendar()

  override func viewDidLoad() {
      super.viewDidLoad()

      service.apiKey = kApiKey

      GIDSignIn.sharedInstance().uiDelegate = self
      GIDSignIn.sharedInstance().scopes = scopes
      GIDSignIn.sharedInstance().signIn()
      GIDSignIn.sharedInstance().delegate = self
  }


  func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {

      if user != nil {
           print("\(user)")
           service.authorizer = user.authentication.fetcherAuthorizer()
           fetchEvents()
      }
  }

 // Construct a query and get a list of upcoming events from the user calendar
   func fetchEvents() {

        let query = GTLQueryCalendar.queryForEventsList(withCalendarId: "primary")
        query?.maxResults = 20
        query?.singleEvents = true
        query?.orderBy = kGTLCalendarOrderByStartTime

        service.executeQuery(query!, delegate: self, didFinish: #selector(ViewController.displayResultWithTicket(ticket:finishedWithObject:error:)))
   }

// Display the start dates and event summaries in the UITextView
    func displayResultWithTicket(
         ticket: GTLServiceTicket,
        finishedWithObject response : GTLCalendarEvents,
        error : NSError?) {

        if let error = error {
            showAlert(title: "Error", message: error.localizedDescription)
            return
        }

        var eventString = ""

        if let events = response.items(), !events.isEmpty {
            for event in events as! [GTLCalendarEvent] {
                print(event)
             }
        } else
                print("No upcoming events found.")
        }
    }

    }

This is how my credentials section appear in Google Dev Console.

enter image description here

Jen Jose
  • 3,995
  • 2
  • 19
  • 36
  • hiiii could u help me with this @Jen Jose...i need to create and save event – Dilip Tiwari Dec 08 '17 at 13:40
  • @DilipTiwari, where are you stuck? Even Dipen 's answer works, but I personally prefer not to meddle with Safari preferences and it's better to use Google authoriser as mentioned in the error. – Jen Jose Dec 09 '17 at 03:21
  • I have followed this link https://developers.google.com/google-apps/calendar/quickstart/ios and successfully showing button and further process to sign in with google and when i add event in web browser with same event i m able to show that on textview in viewcontroller but i want to know how to create event and save in ios app swift @Jen Jose – Dilip Tiwari Dec 09 '17 at 04:09
  • if u have i can talk u through skype or personal chat – Dilip Tiwari Dec 09 '17 at 04:09
  • i integrating the Google Sign and enabling Google Calendar API correctly and it is working but how will work with Google Calendar API to fetch and add Calendar Events.need help – Dilip Tiwari Dec 18 '17 at 11:19
  • I tried the way you suggested, but, I am not able to fetch the events from calendar, can you please help here? – Anilkumar iOS - ReactNative Jul 12 '18 at 05:41
  • and getting this error NSError domain: "com.google.GTLJSONRPCErrorDomain" - code: 401 0x000060000045d130 – Anilkumar iOS - ReactNative Jul 12 '18 at 06:00
  • Can you please check this issue getting while fetching events from google calendar https://stackoverflow.com/questions/51298936/getting-nserror-domain-com-google-gtljsonrpcerrordomain-while-fetching-google @JenJose – Anilkumar iOS - ReactNative Jul 12 '18 at 09:26
  • THANK YOU SOOOOO MUCH BROTHER! – ami rt Aug 04 '18 at 10:45
1

After the google sign-in finishes the login, use the currentUser to get the fetcherAuthorizer, this can be used like an authorizer for the Google Drive Service.

After that you can use the Google Drive Service normally:

GIDGoogleUser *googleUser = [GIDSignIn sharedInstance].currentUser;

if(googleUser != nil){
    self.service.authorizer = googleUser.authentication.fetcherAuthorizer;
    [self listFiles];

}
AP.
  • 8,082
  • 2
  • 24
  • 33
1

This is working for me

mWebView.getSettings().setUserAgentString("Mozilla/5.0 (Linux; Android 4.1.1; Galaxy Nexus Build/JRO03C) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19");
tech.mohit.garg
  • 631
  • 8
  • 18
0

Error 403: disallowed_useragent

Few days ago facing same issue, thought to post here. I was trying to login with Google.

enter image description here

Browser is not compatible with the device. When you open web-view need to add few lines for code in order to work. Steps

  1. In Web-view declare string variable called userAgent and While loading request use this customUserAgent property assign userAgent to it.
let userAgent = "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36 Mozilla/5.0(iPad; U;CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10(KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10"
  if let url = URL(string: mandateUrl){
     let request = URLRequest(url: url)
     webView.customUserAgent = userAgent
     webView.load(request)  
}
Sanjay Mali
  • 506
  • 6
  • 13
0

Error 403: disallowed_useragent You can’t sign in from this screen because this app doesn’t comply with Google’s secure browsers policy. If this app has a website, you can open a web browser and try signing in from there.

You can let the app developer know that this app doesn’t comply with Google’s secure browsers policy. Learn more Request Details HelpPrivacyTerms

-1

I solved the issue it took 1 year :-) just kidding. just add the below line in preference in config.xml

<preference name="OverrideUserAgent" value="Mozilla/5.0 Google" />

Please note i solved this google login issue with Inapp browser.

Thanks

Prosenjeet Paul
  • 284
  • 2
  • 8
-1

I was getting error: "403 Error - Thats an error. Error: disallowed_useragent" on Google Signin InAppBrowser and for my situation the fix was adding userAgent property like this in Webview:

 <WebView
 // other props here
  userAgent={"Chrome/56.0.0.0 Mobile"}
 />
Akshita Agarwal
  • 235
  • 3
  • 4