문제

Attached is a screenshot of my google credentials window with my redirect URIs and on the right the redirectURI registered by the Nodejs Google OAuth2 client that it is sending in the request yet my the response still returns redirect_uri_mismatch

Any idea?

google redirect mismatch

도움이 되었습니까?

해결책 2

Turns out the problem arose because I was trying to exchange a non offline access_type provided to me via the frontend google plus js api. I could not find a way to retrieve a full offline access code from google via their popup to send to my server to exchange for a long living token.

I built my own popup redirect flow. I could not find any resources for the correct way to do a full auth with a popup without redirecting the main page so I improvised. I'm open to improvements but this works for me, anyways if anyone wants to do this also here's my workflow.

How to Set up your own popup oauth authentication flow

You will need to pass the auth url to the front end which the nodejs googleapis library makes easy with:

url = this.oauth2Client.generateAuthUrl(access_type: 'offline', scope: myScope)

Pass that to the front-end somehow, next when the user initiates the oauth button on the website it opens the popup (request 1), and at the same time sends a request (request 2) which waits for the final result

// Front end Angular function to initiate the popup
signup: function(callback) {
  this.$window.open(googleOauthURL, 'Authenticate Google', 'width=600, height=600');
  return this.$http.get('auth/google/awaiting').success(function(res) {
    return callback(res);
  });
}

On the backend here's the coffeescript code which responds to request 2. I added a 150 second timeout, which says: if we don't get a response from the user with his auth credentials within 150 seconds then close the connection. (we don't want hanging connections)

exports.awaiting = (req, res) ->
    # Build a unique listener for the correct ip address
    listener = 'oauthAwait-' + req.ip

    # Clear any possible pre-existing listener
    google.removeAllListeners(listener)

    timeoutProtect = setTimeout ->
        google.removeAllListeners(listener)
        timeoutProtect = null

        res.json
            success: false
            error: 'Timedout'
            data: null
    , timeoutLength

    google.once listener, (result) ->
        if timeoutProtect
            clearTimeout(timeoutProtect)

            res.json(result)# return the data

Next we wait on the user to authenticate the popup. When they do it will redirect to the redirect uri we specified in our dev console. Our server will get the code, make a request to google for the long living access_token, with that we have what we need.

exports.oauthCallback = (req, res) ->
    listener = 'oauthAwait-' + req.ip

    successCallback = (user) ->
        user.success = true
        # trigger the request 2 listener with the data
        google.emit(listener, user)

    failCallback = (err) ->
        error.success = false
        google.emit(listener, error)

    exchangeToken(req, req.query.sessionState)
        .then(doSomethingWithToken, failCallback)
        .then(successCallback, failCallback)
        .fin ->
            # return a page that closes itself to the popup (request 1)
            res.render 'oauthPopupCallback'

Here the we exchange the token then do something with it. Once we get the user we trigger the event emitter listener that we binded in the exports.awaiting section which will return our data to the application, and finally we send a simple html page to the popup with a javascript one liner that says window.close()

Then there we have a fully authenticated user access_token on the back end. This could be improved by using the web sockets if the user supported it, to replace the hanging request.

Edit
Found out there's this dandy method available on popups called window.opener which gives access to the window that opened the popup. Essentially this replaces the need for request 2 that hangs and waits for the response of the popup.

In your popup, you can have a javascript that passes the data along to the main window like:

var service = ResponseData,
    callback = 'on' + service.name + 'Auth';

window.onload = function () {
    window.opener[callback](service.data);
    window.close();
}

다른 팁

Just to add another reason for the uri mismatch error. If you are generating the token on the client side and trying to call getToken on the server side, the REDIRECT_URI must match the client side domain and be added to console APIs.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top