Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticating with OAuth2 on iOS

I am currently trying to authorize my users with OAuth2. I am currently using the following library: https://github.com/p2/OAuth2

let oauth2 = OAuth2CodeGrant(settings: [
        "client_id": "my-id",
        "authorize_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://www.googleapis.com/oauth2/v3/token",
        "scope": "profile",     // depends on the API you use
        "redirect_uris": ["com.TestAuthorizeApp:/oauth2Callback"],
        ])

    //let oauth2 = OAuth2CodeGrant(settings: settings)
    oauth2.onAuthorize = { parameters in
        print("Did authorize with parameters: \(parameters)")
    }
    oauth2.onFailure = { error in        // `error` is nil on cancel
        if let error = error {
            print("Authorization went wrong: \(error)")
        }
    }

    oauth2.authConfig.authorizeEmbedded = false
    oauth2.authorize()

When I run this it loads up google in the browser and I am able to sign in. It then asks me about the permissions I have declared in the scope and that works fine. I click ok open and it redirects me back to my app.

However when I run this code again I am expecting that the access token has been stored in the key chain. However this doesn't seem to be working.

I have looked inside the source code and found the following check: tryToObtainAccessTokenIfNeeded which always returns false. This means I get the page again where I need to click 'Allow'.

I was wondering if someone could help me figure out why it's not saving anything in the keychain. Also does this mean the user is not really being authenticated?

Thanks.

===

Edit

Have added oauth2.verbose = true as per Pascal's comment. I get the following output.

 OAuth2: Looking for items in keychain
 OAuth2: No access token, maybe I can refresh
 OAuth2: I don't have a refresh token, not trying to refresh

Which is what I thought was happening. However I am still unsure as to why it's not saving / finding anything in the keychain.

=====

Edit 2

It turns out that I wasn't actually getting an access token back at all. Please see this conversation: https://github.com/p2/OAuth2/issues/109 and my answer below.

like image 865
pls Avatar asked May 12 '16 13:05

pls


People also ask

What is OAuth2 in iOS?

OAuth2 lets users grant third-party apps access to their web resources, without sharing their passwords, through a security object known as an access token. It's impossible to obtain the password from the access token, since your password is kept safe inside the main service.

Does Apple support OAuth2?

Overview. Starting with iOS 12 and macOS 10.14, Apple has added OAuth 2.0 support for Exchange ActiveSync accounts that can be deployed through an Enterprise Mobility Management.

Can OAuth2 be used for authentication?

The OAuth 2.0 specification defines a delegation protocol that is useful for conveying authorization decisions across a network of web-enabled applications and APIs. OAuth is used in a wide variety of applications, including providing mechanisms for user authentication.


1 Answers

With the help from Pascal here: https://github.com/p2/OAuth2/issues/109 I have managed to get it working. Turns out that I wasn't implementing step: '3 Authorize the User' as I should have been.

So a complete solution is:

Inside my view controller I have the following:

let OAuth2AppDidReceiveCallbackNotification = "OAuth2AppDidReceiveCallback"

override func viewDidLoad() {
    super.viewDidLoad()

    // This notification is for handling step 3 in guide.
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.handleRedirect(_:)), name: OAuth2AppDidReceiveCallbackNotification, object: nil)
}

func authoriseUser {
    let oauth2 = OAuth2CodeGrant(settings: [
        "client_id": "my-id", // Use own client_id here
        "authorize_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://www.googleapis.com/oauth2/v3/token",
        "scope": "profile",     // depends on the API you use
        "redirect_uris": ["com.TestAuthorizeApp:/oauth2Callback"],
        ])

     //let oauth2 = OAuth2CodeGrant(settings: settings)
     oauth2.onAuthorize = { parameters in
        print("Did authorize with parameters: \(parameters)")
     }
     oauth2.onFailure = { error in        // `error` is nil on cancel
         if let error = error {
             print("Authorization went wrong: \(error)")
         }
     }

     oauth2.authConfig.authorizeEmbedded = false
     oauth2.authorize()
 }

// This method gets called by notification and is the last thing we need to do to get our access token. 
func handleRedirect(notification: NSNotification) {
    oauth2.handleRedirectURL(notification.object as! NSURL)
}

The above code should handle sending you to the google web page where you can log in and then click allow.

Now you need to handle returning to the app in the app delegate:

 let OAuth2AppDidReceiveCallbackNotification = "OAuth2AppDidReceiveCallback"

 func application(application: UIApplication,
                 openURL url: NSURL,
                         sourceApplication: String?,
                         annotation: AnyObject) -> Bool {
    // you should probably first check if this is your URL being opened
    NSNotificationCenter.defaultCenter().postNotificationName(OAuth2AppDidReceiveCallbackNotification, object: url)

    return true
}

Hopefully this will help anyone else who might be having issues trying to get an access token.

like image 71
pls Avatar answered Sep 28 '22 06:09

pls