Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication with Google: not matching redirect URL #10

Closed
fabiomassimo opened this issue Jun 11, 2016 · 34 comments
Closed

Authentication with Google: not matching redirect URL #10

fabiomassimo opened this issue Jun 11, 2016 · 34 comments

Comments

@fabiomassimo
Copy link
Contributor

fabiomassimo commented Jun 11, 2016

I was trying to perform a login with Google Service.

Hereby the executed code

let provider = Provider.Google(clientID: "$(the_client_id)", clientSecret: "$(the_client_secret)", redirectURL: "$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob")

provider.scopes = ["https://www.googleapis.com/auth/analytics.readonly"]

provider.authorize(self) { (result) in
    switch result {
    case .Success(let token):
        print(token)
    case .Failure(let error):
        print(error)
}

When the authorisation is granted in the Safari View Controller the redirect URL gets triggered with following format:

$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob?code=$(the_authorization_code)

This cause an issue for when the library checks if the redirect URL use during the initialisation of the Provider matches the received redirect URL from the AppDelegate.

I've tried other combination of redirect URL but that's the redirect URL format that the Google guide advocates.

Did anyone experienced this when trying the built in Google Provider?

I think an easy fix would be to match the retrieved URL by removing the GET parameter from the URL but before open a new PR I'd like to receive some feedback about this.

@fabiomassimo fabiomassimo changed the title Authentication with Google Authentication with Google: not matching redirect URL Jun 11, 2016
@delba
Copy link
Owner

delba commented Jun 11, 2016

redirectURL: "$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob")
$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob?code=$(the_authorization_code)

They look like matching to me. What's the issue?

I think an easy fix would be to match the retrieved URL by removing and GET parameter from the URL

Removing what?

@fabiomassimo
Copy link
Contributor Author

Removing what?

The ?code=$(the_authorization_code) at the end of the URL which makes it different from the redirect URL used to initialise the provider.

@delba
Copy link
Owner

delba commented Jun 11, 2016

We need the code param. https://github.com/delba/SwiftyOAuth/blob/master/Source/Provider.swift#L220

This is how OAuth works. Also, the two URL are matching. We don't compare the query string.
https://github.com/delba/SwiftyOAuth/blob/master/Source/Provider.swift#L252

@delba delba closed this as completed Jun 11, 2016
@delba
Copy link
Owner

delba commented Jun 11, 2016

We need the code param in order to exchange it for a token. This is how OAuth works.

@fabiomassimo
Copy link
Contributor Author

fabiomassimo commented Jun 11, 2016

Sorry I'm not being clear enough.

I do not want to remove that part from the URL for the OAuth authorisation flow but only for checking if it matches the redirect URL used to initialize the provider.

More in detail this code fails:

    func matchingURLs(a: NSURL, _ b: NSURL) -> Bool {
        return (a.scheme, a.host, a.path) == (b.scheme, b.host, b.path)
    }

That's because

print(a.host) returns

 urn:ietf:wg:oauth:2.0:oob?code=$(the_authorization_code)

while b.host returns

 urn:ietf:wg:oauth:2.0:oob

My idea is to improve to implement an improved getter to retrieve the proper host from the URL.

@delba
Copy link
Owner

delba commented Jun 11, 2016

I don't get the same result.

let url = NSURL(string: "foo://urn:ietf:wg:oauth:2.0:oob")!
print(url.host) // "urn"

let redirect = NSURL(string: "foo://urn:ietf:wg:oauth:2.0:oob?code=abc123")!
print(redirect.host) // "urn"

@delba
Copy link
Owner

delba commented Jun 11, 2016

Maybe you could change the redirect URL to something else ?

@fabiomassimo
Copy link
Contributor Author

If I try to use // instead of / I get an error in the Google page.

I tried a lot of combinations but only that one is working for me :(

@delba
Copy link
Owner

delba commented Jun 11, 2016

I got nil for both of them when using only one /

@fabiomassimo
Copy link
Contributor Author

Thank you for your feedback.

I'll try again by using the Provider to find out what is causing this behaviour about different host output.

I'll publish the results later in case someone else will have the same issue.

@delba
Copy link
Owner

delba commented Jun 11, 2016

Yes, let me know please :)

@delba
Copy link
Owner

delba commented Jun 11, 2016

Hey @fabiomassimo ,

You might want look at the next branch. Here is how to use it with Google:

let google: Provider = {
    let provider: Provider = .Google(clientID: "***", clientSecret: "***", redirectURL: "http://anything.com/callback")
    provider.useWebView = true
    return provider
}()

Note that you can set the redirectURL to anything you want so it might solve your issue when working with Google.

I tried it with Instagram, Dribbble, Github etc. Let me know if it works with Google and I'll be happy to merge it in master.

Thanks!

@fabiomassimo
Copy link
Contributor Author

Unfortunately with any callback URL I get back following error:

Invalid parameter value for redirect_uri: Invalid scheme.

The only combination the works for me is with following format:

$(bundle_identifier):/urn:ietf:wg:oauth:2.0:oob // with only one /

Should we mention this in the README?

Last but not least the URL matching algorithm works great now. I got my token back.

@fabiomassimo
Copy link
Contributor Author

And this is mandatory too:

google.scopes = ["$(a_google_scope)"]

@delba
Copy link
Owner

delba commented Jun 11, 2016

I meant set the callback to "http://myValidCallback.com/callback". Literally ahaha

When using webviews, we only listen for the redirectURL. We don't use it to open the app.

What are the mandatory scopes please?

@fabiomassimo
Copy link
Contributor Author

What are the mandatory scopes please?

A lot: https://developers.google.com/identity/protocols/googlescopes

@fabiomassimo
Copy link
Contributor Author

You have to specify at least one

@delba
Copy link
Owner

delba commented Jun 11, 2016

I'll leave the scopes part to the user. But if it works, I'll specify provider.userWebView = true in the .Google func.

@fabiomassimo
Copy link
Contributor Author

That's a good idea.

Maybe a link in the README or commented in the code to the list of available scopes?

@delba
Copy link
Owner

delba commented Jun 11, 2016

I'll add a page to the wiki if useWebView works. Let me know please

@fabiomassimo
Copy link
Contributor Author

It works great but only with callback format specified before.
Anything starting with http or another scheme gets an error.

Is it what you meant?

@delba
Copy link
Owner

delba commented Jun 11, 2016

I tested with the redirectURL "http://www.hello.com/callback" and it works

let google: Provider = {
    let provider: Provider = .Google(
        clientID: "***",
        clientSecret: "***",
        redirectURL: "http://www.hello.com/callback"
    )
    provider.scopes = ["https://www.googleapis.com/auth/adexchange.buyer"]
    provider.useWebView = true
    return provider
}()

@fabiomassimo
Copy link
Contributor Author

I get back from Google in the browser:

redirect_uri_mismatch

Same init as yours but with different scope.

@delba
Copy link
Owner

delba commented Jun 11, 2016

You have to update the redirect on url google...

@fabiomassimo
Copy link
Contributor Author

fabiomassimo commented Jun 11, 2016

Where should I update it?

I receive the error with following Provider

    let google: Provider = {
        let provider: Provider = .Google(clientID: "***", clientSecret: "***", redirectURL: "http://www.hello.com/callback")
        provider.useWebView = true
        provider.scopes = ["https://www.googleapis.com/auth/analytics.readonly"]
        return provider
    }()

@delba
Copy link
Owner

delba commented Jun 11, 2016

@delba
Copy link
Owner

delba commented Jun 11, 2016

I did another try with http://hello.com/callback, it works well. Sorry

@fabiomassimo
Copy link
Contributor Author

Weird but anyway it is not blocking because the Provider works with my strange redirect URL when using a WebView 👍

I think it is ok to merge next to master

@delba
Copy link
Owner

delba commented Jun 11, 2016

It's because you didn't update the redirect URL on https://console.developers.google.com

@fabiomassimo
Copy link
Contributor Author

Yep looking into that right now ;)

@fabiomassimo
Copy link
Contributor Author

fabiomassimo commented Jun 11, 2016

It seems that because it is an iOS app I can only enter my bundle identifier and Google uses that to create a proper redirect URL. I can not see where I can set the redirect URL.

Anyway, I'll look into this better in the docs. Thank you.

UPDATE: Indeed, I can set a custom redirect URL if I create a OAuth credential for a web client.

@delba
Copy link
Owner

delba commented Jun 11, 2016

Again, it works with http://hello.com/callback. With an iOS app.

I can not see where I can set the redirect URL.

Did you register on https://console.developers.google.com ?

@fabiomassimo
Copy link
Contributor Author

fabiomassimo commented Jun 11, 2016

This is what I get for iOS settings:

screen shot 2016-06-11 at 22 33 01

This is what I get for Web Application settings:

screen shot 2016-06-11 at 22 33 10

@delba
Copy link
Owner

delba commented Jun 12, 2016

I just pushed v0.4 😃

Use it with Google (and web server) like so:

let google: Provider = {
    let provider: Provider = .Google(clientID: "***", clientSecret: "***", redirectURL: "http://www.hello.com/callback")
    provider.useWebView = true
    provider.scopes = ["https://www.googleapis.com/auth/analytics.readonly"]
    return provider
}()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants