Admin API token exchange on Node.js vs Python

773
2
05-20-2022 05:42 PM
JVig
by
New Contributor II

TL;DR: Why does Node.js have a different response to exchanging a token in the header vs Python when trying to reach an admin endpoint using a standalone ArcGIS for Server architecture?

Hello fellow GIS Devs! I've been building out a command line interface to help with some of my administrative tasks using ArcGIS Server 10.7.1 (NOT PORTAL just the standalone server) using node.js, as we plan on upgrading our system to Portal in the future. Because I am not using Portal, I believe the Oath2 workflows will not necessarily work for me. Now to my problem: for some reason in when using Node.js I run into an error regarding the clientID:

{
  status: 'error',
  messages: [ 'Invalid token, ClientID does not match.' ],
  code: 498
}

I am using Axios to connect to the administration endpoint and using an interceptor to set the token as an Authorization header for the requests. I have verified the successful return of my token along with it being applied to the GET request at the <myarcserver>/arcgis/admin/services/<folder> endpoint. And yet, I still get the error above which appears to be an Oath2.0 error. Below is a snippet of my instance module along with the module calling it. Please don't make fun of me, I'm just starting to learn Node 😄

Instance snippet:

const baseURL = new URL(`${host}/arcgis/admin`).href;

    const headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'application/json'
    };
    const payload = new URLSearchParams({
        username: process.env.GDS_USER,
        password: process.env.GDS_PASS,
        client: 'referer',
        referer: baseURL,
        f: 'json'
    });

    let token = null;

    const axiosInstance = axios.create({baseURL: baseURL});

    axiosInstance.interceptors.request.use(async config => {
        if (!token) {
            const { data } = await axios({
                url: `${baseURL}/generateToken`,
                method: "post",
                data: payload,
                headers: headers
            })
            token = data.token;
        }

        config.headers.Authorization = `Bearer ${token}`;

        return config
    });

 And here is the function that calls it when the command line command is invoked:

export const listServices = (folder, env) => {
    const arc = arcServer(env);

    return arc({
        url: `/services/${folder}`,
        method: "get",
        params: {
            f: 'json',
        }
    })
    .then(response => {
        console.log(response.data)
    })
    .catch(error => {
        return Promise.reject(error)
    });
    

}

And a screenshot of the response:

JVig_0-1653093331795.png

 

Finally, I have written something similar to this in the past using python and have had zero issue connecting to it, even now.

def get_token(self):
        """
        Acquires the token necessary to access the administration endpoints. Tokens
        are limited to 600 seconds before expiration.
        """
        url = f'{self.server}:6443/arcgis/admin/generateToken'
        headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}

        params = {
            'username': self.user,
            'password': self.password,
            'client': 'referer',
            'referer': self.referer,
            'f': 'json'
        }

        r = self.session.post(url, data=params, headers=headers)

        if r.status_code == 200:
            response = json.loads(r.text)
            if response.get('token'):
                self.session.headers.update({'Authorization': f'Bearer {response["token"]}'})

                return response['token']
            else:
                if response.get('error'):
                    e = response['error']
                    raise ArcGISServerException('Generate token failed: {}'.format(e))
                else:
                    raise ArcGISServerException('Generate token failed')
        else:
            raise ArcGISServerException('Generate token failed, server response code: {}'.format(r.status_code))

 

So what's the difference here? Am I just a node amateur? Why is the admin services directory requesting a client ID when using one language, but not the other?

As always, appreciate y'all's help. ❤️

 

/Jason

2 Replies
Raul_Jimenez
Esri Contributor

Hi Jason,

I'm more a JS developer. I have never sent the token in the header, I have always send the token as another parameter.

It would help to see a copy of both CURL requests (removing the tokens/domains) to better understand what might be happening, but it doesn't make sense to me either.

I'm going to share a few resources that might help you with this:

I hope this helps

 

 

JVig
by
New Contributor II

Thanks, I'll have a look at this!

0 Kudos