質問

I'm creating an OAuth authentication flow so users of my installed application can access their private Google spreadsheet documents. I'm coding with Adobe ExtendScript, so I cannot use the Javascript client libraries Google provides. I've read Google's OAuth 2.0 documentation for installed applications quite a few times, but need help with one aspect of the OAuth flow. I am able to get an authorization code by launching a browser from the installed app, and having the user submit their credentials, and then copy and pasting the authorization code back into the app. However, when I POST to the endpoint for exchanging the authorization code for an access token, it doesn't work. The body of the response from google shows this:

Moved Temporarily
The document has moved <A HREF="https://accounts.google.com/o/oauth2/token">here</A>.

And yet, I made the POST call to that exact same URL found in the href tag. So, I'm not sure why google would tell me that the end point has moved temporarily when I POSTed to that same URL. Here is the code I'm using to generate the POST.

function getAccessToken(authcode)
{
    var http = require('http'),
        OAuthAccessEndPoint = 'https://accounts.google.com/o/oauth2/token',
        OAuthAccessParams = {};

    OAuthAccessParams['code']             = authcode;
    OAuthAccessParams['client_id']        = '{my_client_id}';
    OAuthAccessParams['client_secret']    = '{my_client_secret}';
    OAuthAccessParams['redirect_uri']     = 'urn:ietf:wg:oauth:2.0:oob';
    OAuthAccessParams['grant_type']       = 'authorization_code';

    var response = http.post(OAuthAccessEndPoint, OAuthAccessParams);

}

The post is made fine, but does anybody know why this 'Moved Temporarily' notice would come up in google's response? Any suggestions are much appreciated!

EDIT: Just to clarify, here is the request my script is making in the raw:

POST /o/oauth2/token HTTP/1.1
User-Agent: Adobe ExtendScript
Accept: */*
Connection: close
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 226

code={authcode}&client_id={my_client_id}&client_secret={my_client_secret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code&

If I use the authorization code in cURL, along with the other params, I do get a successful response from Google's OAuth servers. So, obviously something is up with the way my sockets are interacting with Google's endpoints, but I'm not sure what. Is it possible that some components need to be URI encoded, while others do not? Here is the cURL I am using:

#!/bin/bash
AUTHCODE="$1"

POSTCONTENT="code=$AUTHCODE&client_id={my_client_id}&client_secret={my_client_secret}&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code&"

echo $POSTCONTENT

curl -v --data $POSTCONTENT https://accounts.google.com/o/oauth2/token

EDIT 2: So, since Sockets do not support SSL in Extendscript, I wrote a function that uses OS level calls to invoke the request. If on OSX, we can assume that we have access to cURL, but on Windows, we have to write a VBScript that gets executed via the cscript host in the command line. For ExtendScript, here is the function that makes the web request:

function webRequest(method, endpoint, query){

    var response = null,
        wincurl  = WORKING_DIR.fsName + '\\lib\\curl.vbs',
        curlCmd = '';

    try {

        if ( os() == "Win" ) {
            curlCmd = 'cscript "' + wincurl + '" /Method:' + method + ' /URL:' + endpoint + ' /Query:' + query + ' //nologo';
        } else {
            if (method === "POST") {
                curlCmd = 'curl -s -d "' + query + '" ' + endpoint;
            } else if (method === "GET") {
                curlCmd = 'curl -s -G -d "' + query + '" ' + endpoint;
            }
        }

        response = system.callSystem(curlCmd);

    } catch (err) {

        alert("Error\nUnable to make a `"+ method +"` request to the network endpoint.  Please try again.");

    }

    return response;

}

function os(){
    var os = system.osName;
    if (!os.length) { os = $.os; }
    app_os =  ( os.indexOf("Win") != -1 )  ?  "Win" : "Mac";
    return app_os;
}

And here is the VBScript script that is called from the ExtendScript library. It takes three params, all strings:

set namedArgs = WScript.Arguments.Named

sMethod = namedArgs.Item("Method")
sUrl = namedArgs.Item("URL")
sRequest = namedArgs.Item("Query")

HTTPPost sMethod, sUrl, sRequest

Function HTTPPost(sMethod, sUrl, sRequest)

    set oHTTP = CreateObject("Microsoft.XMLHTTP")  

    If sMethod = "POST" Then
        oHTTP.open "POST", sUrl,false
    ElseIf sMethod = "GET" Then
        oHTTP.open "GET", sUrl,false
    End If

    oHTTP.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    oHTTP.setRequestHeader "Content-Length", Len(sRequest)
    oHTTP.send sRequest

    HTTPPost = oHTTP.responseText

    WScript.Echo HTTPPost

End Function 

You can use this in ExtendScript for any API endpoint, but the response will always be a string. So, in the case of Google's OAuth Endpoints, you'll get a string that looks like JSON. So, y ou'll have to parse it with something like JSON.parse().

役に立ちましたか?

解決

See edits above for the answer to this. Essentially it boiled down to Socket objects in ExtendScript not supporting SSL. The solution above shows a workaround by using ExtendScript system.callSystem() method to get at cURL on OSX and a VBScript on Windows.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top