How to add bearer token in POST endpoint py file?

Can anybody help how to set a py endpoint to receive POST notification with bearer token or other authorization? If without bearer token, I can received data with frappe.form_dict, but with bearer token, I got http 417 in nginx.

Please advice, thanks!

Can you be a bit more explicit about what you are trying to do and how you are trying to do it? Where are you getting the bearer token that you are sending?

Hi peterg, thanks for the reply
I subscribed to a service that provides JSON of my latest bank transactions every 10 minutes to a py endpoint file (/www/banktransaction/index.py) in my server: https://myserver/banktransaction
this is what I got from their doc API

import json

url = "https://myserver/banktransaction"

payload = json.dumps([
  {
    "mutasi_id": "1100",
    "date": "2019-09-29 14:00:03",
    "type": "D",
    "module": "bca",
    "description": "TRSF E-BANKING DB 2909/FTFVA/WS9501112008/SHOPEE - - 05000369188",
    "amount": "92000.00"
  },
  {
    "mutasi_id": "1109",
    "date": "2019-10-01 01:07:04",
    "type": "K",
    "module": "bca",
    "description": "BUNGA ",
    "amount": "5646.50"
  }
])
headers = {
  'X-API-KEY': 'Your API Key',
  'Content-Type': 'application/json'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)

I’m still not really following. Where are you trying to put this code? How, when, and from where are you trying to call an ERPNext API? Most importantly, how are you generating the bearer token that is resulting in a 417 error (which likely means an incorrect bearer token)?

the provider will send notification with header X-API-KEY and body of JSON as mention above every 10 minutes to a URL I provided to them
the URL is https://myserver/banktransaction
I set it up from /frappe-bench/apps/custom-app/custom-app/www/banktransaction/index.py
right now the content is just print(f"{frappe.form_dict}")

If the provider POST data to this URL, my server will throw http code 417
so I will need somehow put X-API-KEY in the code to recognize this POST, or is not?

Ah, I see. I thought you were both sending and receiving.

I don’t think you can create an API endpoint just by sticking an index.py file at an exposed web address. Is that a convention from another framework, perhaps? If it works for Frappe, I’ve never seen it before. Where are you seeing this approach?

Generally, if you want to create an API endpoint in frappe, you need to write a python method that handles the requests and then whitelist it using the @frappe.whitelist() decorator. In this case, you’d probably need to allow guest access by making it @frappe.whitelist(allow_guest=True).

Details: https://frappeframework.com/docs/v13/user/en/api/rest#remote-method-calls

(What’s confusing me here is that you say it works if there’s no token but doesn’t work if a token is present. I’m not sure how that could be the case.)

Got it
I used this approach from 2 frappe youtube channels.
So I have to create inside some doctype and decorate it with whitelist and allow guest to access it, right?
Is there a way to add validation in the py file that the header should be X-API_KEY equals to XXXXX?

It doesn’t have to be in a doctype. It could be in any file addressable by python or in a server script.

Sure, just check the frappe.request.headers object and throw an error if there’s no matching X-API_KEY. This isn’t a bearer token like you’d get from oauth. It’s just a shared secret you can use to make sure strangers don’t spam your endpoint.

Is there a sample py file that do similar behavior that you can suggest?

This is just off the top of my head, but something like…

api_key = [header for header in frappe.request.headers if header[0] == 'X-API_KEY']
if not len(api_key):
     frappe.throw("API Key not found in request header.")
if api_key[0][1] != "API KEY SECRET"
     frappe.throw("API Key does not match")

…should work.

okay, let me try that later
Thanks for the snippet