1

Following on from https://lists.hyperledger.org/g/composer/message/91

I have adapted the methodology described by Caroline Church in my IOS app. Again I can authenticate with google but still get a 401 authorization error when POSTing.

I have added the withCredentials parameter to the http header in my POST request.

does the rest server pass back the token in cookie ? I don't receive anything back from the rest server.

where does the withCredentials get the credentials from ?

COMPOSER_PROVIDERS as follows

COMPOSER_PROVIDERS='{
    "google": {
        "provider": "google",
        "module": "passport-google-oauth2",
        "clientID": "93505970627.apps.googleusercontent.com",
        "clientSecret": "",
        "authPath": "/auth/google",
        "callbackURL": "/auth/google/callback",
        "scope": "https://www.googleapis.com/auth/plus.login",
        "successRedirect": "myAuth://",
        "failureRedirect": "/"
    }
}'

the successRedirect points back to my App. After successfully authenticating I return to the App.

Arnab
  • 4,216
  • 2
  • 28
  • 50
Jamil Ahmed
  • 35
  • 2
  • 4
  • Hi, how do You fetch access token from mobile app on iOS? I can not find how to get it. thanks – Doro Jul 19 '18 at 14:18
  • Hi, as I mentioned in my answer below once you have the authorization code, call the callback URL of the rest server and pass the code as a parameter. The call returns a failure code but if you check your cookies you should find the access token cookie. Are you able to call the callback URL ? do you get a response ? – Jamil Ahmed Jul 21 '18 at 10:57
  • Could you please share a code snippet for this flow? I can not understand what I should call after I've got authenticated. I'm using SFAuthenticationSession for sso – Doro Jul 23 '18 at 09:22
  • My callback url: "/auth/google/callback". From ios app I'm calling this and receive some cookies but without access token. What "code" should I pass to callback as parametr? – Doro Jul 24 '18 at 07:41
  • I have added the code in the answer section below, I hope it helps. – Jamil Ahmed Jul 24 '18 at 10:29
  • the code is the authorization code received back from google after authentication – Jamil Ahmed Jul 24 '18 at 10:37

3 Answers3

1

Got this working now. The App first authenticates with google then exchanges the authorization code with the rest server.

The Rest server COMPOSER_PROVIDERS needs to be changed to relate back to the app. clientID is the apps ID in google, callbackURL and successRedirect are reversed_clientID://

The App calls http://localhost:3000/auth/google/callback with the authorization code as a parameter.

this call will fail, but an access_token cookie is written back containing the access token required for the rest server.

The user id of the logged in user is not passed back, when exchanging the code for a token with google we get back a JWT with the details of the logged in user. We need this back from the rest server as well as the token. Is there any way to get this ?

changing the COMPOSER_PROVIDERS means that the explorer interface to the Rest server no longer works.

Jamil Ahmed
  • 35
  • 2
  • 4
  • Do we need to change callback url to reversed client id? what will happen in this case? – Doro Jul 23 '18 at 09:49
1
func getRestToken(code: String) {        
    let tokenURL = "http://localhost:3000/auth/google/callback?code=" + code

    let url = URL(string:tokenURL);

    var request = URLRequest(url: url!);

    request.httpMethod = "GET";

    request.setValue("localhost:3000", forHTTPHeaderField: "Host");

    request.setValue("text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8", forHTTPHeaderField: "Accept");
    request.setValue("1", forHTTPHeaderField: "Upgrade-Insecure-Requests");

    request.httpShouldHandleCookies = true;
    request.httpShouldUsePipelining = true;

    let session = URLSession.init(configuration: .default);
    session.configuration.httpCookieAcceptPolicy = .always;
    session.configuration.httpShouldSetCookies=true;
    session.configuration.httpCookieStorage = HTTPCookieStorage.shared;

    let task = session.dataTask(with: request) { (data, response, error) in
            var authCookie: HTTPCookie? = nil;
            let sharedCookieStorage = HTTPCookieStorage.shared.cookies;

            // test for access_token
            for cookie in sharedCookieStorage! {
                if cookie.name == "access_token"
                {
                    print(“Received access token”)
                }
            }

            guard error == nil else {
                print("HTTP request failed \(error?.localizedDescription ?? "ERROR")")
                return
            }
            guard let response = response as? HTTPURLResponse else {
                print("Non-HTTP response")
                return
            }
            guard let data = data else {
                print("HTTP response data is empty")
                return
            }

            if response.statusCode != 200 {
                // server replied with an error
                let responseText: String? = String(data: data, encoding: String.Encoding.utf8)

                if response.statusCode == 401 {
                    // "401 Unauthorized" generally indicates there is an issue with the authorization
                    print("Error 401");
                } else {
                    print("HTTP: \(response.statusCode), Response: \(responseText ?? "RESPONSE_TEXT")")
                }
                return
            }

        }

    task.resume()

}
Jamil Ahmed
  • 35
  • 2
  • 4
0

have you authorised the redirect URI in your Google OAUTH2 configuration ?

This determines where the API server redirects the user, after the user completes the authorization flow. The value must exactly match one of the redirect_uri values listed for your project in the API Console. Note that the http or https scheme, case, and trailing slash ('/') must all match.

This is an example of an Angular 5 successfully using it Angular 5, httpclient ignores set cookie in post in particular the answer at the bottom Scope controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.

see https://developers.google.com/identity/protocols/OAuth2

The withCredentials option is set, in order to create a cookie, to pass the authentication token, to the REST server.

Finally this resource may help you https://hackernoon.com/adding-oauth2-to-mobile-android-and-ios-clients-using-the-appauth-sdk-f8562f90ecff

Paul O'Mahony
  • 6,740
  • 1
  • 10
  • 15
  • I have created two OAUTH2 clients. One web client with the required redirect URIs and one for the IOS App. The hacker noon article suggests using AppAuth, I have tried using. this. Access tokens received back from AppAuth after authentication do not look like the tokens produced by the rest server. If I try and use them by supplying them on my request URLs I receive Authorization required errors. I assume that these are from Google. Hence my query earlier on how to receive access tokens from the rest server. – Jamil Ahmed May 10 '18 at 15:57
  • Are you getting back an Authorisation code - that you need to exchange for a base64 access token? Then you need to pass the that token as a Header,. This curl demonstrates just one example: curl -X GET --header 'X-Access-Token: htnNqL0zD9NGwtl30y6uBt6uKws6nnWjxDzYbYUylortAm4pmjW1x4x0f0vknd0z2' 'http://localhost:3000/api/Trader' . On mobile - have you seen these : https://developers.google.com/identity/protocols/OAuth2InstalledApp and https://developers.google.com/actions/identity/oauth2-code-flow ` – Paul O'Mahony 16 mins ago – Paul O'Mahony May 11 '18 at 11:20
  • yes I do get an authorization code, AppAuth already exchanges this for an access code with google which does not look like access tokens that the rest server explorer displays. These always start with ya29. and are much longer. Should the exchange happen thru the rest server or directly with google ?, currently my app authenticates directly with google and exchanges tokens with google. Is this correct ? if not then which URL do I use to exchange tokens ? – Jamil Ahmed May 14 '18 at 07:07
  • hi Jamil - I think the issue therefore is you need to get a JWT token (eg 64 chars) not the Google OAUTH2 token (ya29: etc) - I understand that the exchange happens between (thru) REST server and Auth provider where client app / REST client auth is concerned - this may help -> https://stackoverflow.com/questions/48623656/why-cant-the-google-jwt-token-be-decoded-by-jwt-io – Paul O'Mahony May 15 '18 at 16:02