3

I have a feature layer that I query from a python script using the ARCGIS REST API. I also call the Geoprocessing service to create buffers, etc. all using a token generated via my [portal_root]/oauth2/token endpoint. The APP ID and Secret that I use were generated in the same portal. All queries work fine, even if the services are not published publicly.

data = {
  'client_id':os.environ['CLIENT_ID'],
  'client_secret':os.environ['CLIENT_SECRET'],
  'grant_type':'client_credentials'
}

response = requests.post('{}/{}'.format(os.environ['PORTAL_ROOT'],'oauth2/token'), data=data, verify=True)

if response.ok== False:
  raise Exception("Could not authenticate to arcgis")
else:
  content = json.loads(response.content)
  token = content["access_token"]
  print('][==Authenticated==][')

I can then do things like:

apiEndpoint='Utilities/Geometry/GeometryServer/buffer'

data = {
  'geometries':json.dumps(quoteLocationGeometry),
  'inSR':4326,
  'outSR':102100,
  'distances':2000,
  'unit':9001,
  'token':token,
  'f':'json'
}

response = requests.post('{}/{}'.format(os.environ['SERVER_ROOT'],apiEndpoint), data=data, verify=True)
# Sprint(response.text)
if response.ok== False:
  raise Exception("Could not get Buffer",response.text)
else:
  quoteLocationBuffer = json.loads(response.content)

This all works fine. The last step in my script is to write some data back to a feature service/layer:

apiEndpoint = 'Hosted/SavedQuotes/FeatureServer/0/addFeatures'

feat = solvedRoutes['routes']['features'][0]
data = {
   'token':token,
   'f':'json',
   'features':json.dumps([{
     'attributes':{
      'details':feat['attributes']['Name'],
      'total_cost':feat['attributes']['Total_Cost'],
      'total_length':feat['attributes']['Total_Length'],
      'SHAPE__Length' : feat['attributes']['Shape_Length'],
      'origin_latitude' : lat,
      'origin_longitude' : lon,
      'rid':args.rid,
      'creator_userid' : 'some user ID or email',
      'creator_email' : '[email protected]',
      'creation_date': int(time.time())*1000
   },
    'geometry':{
      'spatialReference':solvedRoutes['routes']['spatialReference'],
      'paths':feat['geometry']['paths']
    }
    }])
   }

print(json.dumps(data))
response = requests.post('{}/{}'.format(os.environ['SERVER_ROOT'],apiEndpoint), data=data, verify=True)

if response.ok== False:
  raise Exception("Could not Save Quote",response.text)

print(response.content)

This call fails with a:

'{"error":{"code":500,"message":"User does not have the privilege to perform this operation.","details":[]}}

If I make the Feature layer public, the write works fine, so I know the API call is formatted correctly. I have a valid Auth token, and all READ operations work fine using this token. I opened a ticket with ESRI and it was closed with "sorry, you can't write to a feature layer using OAuth. The layer has to be public. I 100% cannot believe this to be the case. Why can't I write to a feature layer using the REST API + OAuth? The ESRI rep kept sending me docs on the Portal Administration REST api, even after me sending the script and describing in detail what I am trying to do, he just keeps saying it's not possible. He did say I could call the generateToken endpoint with a username and password, but the docs state that interface is superseded by OAuth, and we use OAuth everywhere. It's not adding up.

1 Answer 1

0

Looks like you don't get full owner privileges to your account resources unless you go through the full OAuth process. For example:

from urllib.parse import urlencode
import requests
import webbrowser

portal_root = 'https://www.arcgis.com/sharing/rest'

params = {
    'client_id': 'YOUR_CLIENT_ID',
    'response_type': 'code',
    'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
    'expiration': 1440
}

auth_url = portal_root + '/oauth2/authorize?' + urlencode(params)
webbrowser.open(auth_url)
auth_code = input('Enter Approval Code: ')

data = {
    'client_id': 'YOUR_CLIENT_ID',
    'grant_type': 'authorization_code',
    'code': auth_code,
    'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
    'f': 'json'
}

auth_response = requests.post(portal_root + '/oauth2/token', data)
token_data = auth_response.json()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.