Multi site requests

I’m making a custom app that does like a ticket system from branch sites to a central site. This is the scenario:


Site A ———> Site B <——— Site C

A and C are the branch sites, B is the central.
A would click a button that will send post request to create new ticket doc in B.

In standard frappe scenario, the user in B would give its user’s key/secret to A and C for them to access api in B.

But in my scenario, the A and C should be able to access B without knowing the B’s key/secret beforehand (because B would not know which sites will access so it can’t give the pair to any sites freely).

The A can do this with the /user.generate_keys api to get B’s secret and /User with api_key field to get the B’s key.

The same can be done by C to access B.

The problem is when C do the same, the request will generate new secret.

Hence when A want to access B again, the key/secret has changed so A can’t reuse the key/secret pair it already got. A has to generate a new secret again.

Is this generate-new-secret-everytime is the way to do it?

Will it add more burden to B to generate secret everytime (think of many sites instead of just 1 or 2)?

What is the more proper way to do such multi parties scenario?

I’m also thinking of using B user’s usr/pwd to access the B api if this is possible.

I’m using version 12 so there is no streaming module like in v13. Even in v13 the key/secret would be generated by B.

Thank you.

Instead of directly accessing API, build a scalable app using pub/sub architecture. This way you publishers will publish and subscribers will get it. This is how typical distributed apps are written these days. This will allow only access to shared queue without the knowledge of who is sending/receiving.

Thanks @shareeef,
I’m not a developer so can you elaborate or point me to a reading resource?
Thanks.

@rahy I was under impression when you said you are developing custom application. I myself am new to erpnext and learning the customizations. But the idea is the branches will generate or publish messages when someone clicks the button and the custom app will listen/subscribe to these messages and post it to master… Check this article at medium: How to get Realtime Updates in your App from ERPNext via Socket.io and Redis | by Parth Joshi | Medium

But I am afraid these needs some development skills.

I think I generally understand the logic of the article. But I don’t need real-time communication of data. It’s only once get and keep. So I think session and/or cookies would do it. Of course, I might be wrong :slight_smile:

On the other hand, the custom app that act as repository of central data to be used is not really useful (again…I think) because if the custom app is installed in every sites, these custom apps still need to communicate among them. If this custom app is installed in the central site, actually the User doctype has already functioning as such.

The article differs from my scenario in that it explained the access from multi applications (mobile, web, etc) to a single site, while my scenario needs access from multi sites to one central site (all sites are the same frappe/erpnext but having different role - central vs branch).

I’m already able to do this token retrieval from one branch site to the central. And use it for the subsequent requests.
But doing it from many sites would change the token everytime.

Are the sites hosted on different servers? Why do you need different keys for different site, same key can be used by your branch sites, isn’t? May be I am not able to understand your question correctly.

Yes

It is the User secret that need to be regenerated. I don’t need it to be if C can reuse the first generated secret (by A). But after A, when C sends requests, it regenerates the secret (C is different site than A, hence can’t share the secret generated by A previously).
I hope I explain the issue clearly.

Your understanding of the keys concept is not clear. Can you give me example what you are trying to do in your app? What is getting regenerated? Once a key is generated it can be reused again and again by multiple sites.

Are you using token based auth? See this tutorial: [Tutorial] Using cURL for REST and RPC API calls - Integration - Discuss Frappe/ERPNext


You are talking about this key and secret, right?

As you said, the key can be reused. But Authorization token needs key:secret pair.
It is secret that will be regenerated because sites can’t share it among them.

Yes.
This is what I do:

#1 - First login to the branch site:

urllog = 'https://mysite.com/api/method/login'
paramlog = {
    'usr': 'administrator',
    'pwd': 'a1b2c3'
}
rlog = requests.post(url, headers=headers, params=paramlog)
return rlog.cookies

#2 - then get user (e.g Administrator) secret:

urlsec = 'https://mysite.com/api/method/frappe.core.doctype.user.user.generate_keys'
paramsec = {
    'user': 'Administrator'
}
rsec = requests.post(urlsec, headers=headers, params=paramsec, cookies=logcookies)

#3 - then get key:

urlkey = 'https://mysite.com/api/resource/User'
paramkey = {
    'fields': '["name","api_key"]',
    'filters': '[["name", "=", "Administrator"]]'
}		
rkey = requests.get(urlkey, headers=headers, params=paramkey, cookies=logcookies)

#4 - then create token:

json_objsec = json.loads(rsec.text)
api_secret = str(json_objsec['message']['api_secret'])

json_objkey = json.loads(rkey.text)
api_key = str(json_objkey['message']['api_key'])

token = "token "+api_key+":"+api_secret

#5 - then use the token on other api to create the custom doctype.

headers = {
    'Authorization': token
}
...

My question is with #2 which using generate_keys api. So each time this requests is called it creates new secret (as intended as in the API Access section of User doctype).
I can’t use frappe.get_doc('User') with field api_secret because it will return ********

@rahy You don’t need to generate the secret every time. You create it once and keep it in your configuration and reuse the same secret again and again. It is like database username and password, you generate it once and reuse it whenever you want to connect to database.

I hope you understand what I am saying.
It is generally a good practice to create an API user, generate the key and secret for that user then reuse in your API.

In your step, you will do step no. 2 only once to get the secret, store that secret and reuse it again and again, my friend.

Do you mean to store the secret in the branch site (the origin of requests) or the central site (the target site)?

By this I mean from other branch sites.

The central site will have a user, say API User, you will generate a key and secret. Use web UI to generate the secret and key.

On the branch site B, you can keep the secret and key in config file where app can use to connect to central site and do the API call.

similarly same secret is used on site C, use the same key and secret to connect to make the call

This way only one secret is generate at A and used at B and C.

Edit: The site A is central and B and C are branches…just to be clear.

  1. As I mentioned at my first post, I don’t want the user in central to create the key/secret from the web UI. It needs to be created from the branch sites that want to send request to create the ticket in central.
  2. If central user creates key/secret, it needs to share the key/secret to branches (which is not known beforehand which will send ticket).
  3. The branches sites can’t share the central’s secrets because they don’t know each other.

How will a branch connect to central site without known key and secret? It does not work the way you are thinking.

Anybody wants to connect to API from outside should have secret and key predefined.

You will need to create a secret and key at origin for any source to connect to that origin.

Using the generate_keys endpoint to return api_secret.
And then frappe.get_doc('User') to get the api_key.

Easiest approach is to create an API user for each branch at the central site, use the secret and key for each branch separately so whenever a new branch is established you can use this process. This way branches don’t have shared secret, they have their own key to talk to central site. It is more secure.

This is for local site at branch, not the central site. You want to talk to central site from branch, right?