-->

Authenticating with OAuth2 on iOS

2020-03-04 03:28发布

问题:

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.

回答1:

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.