Receive Backend Requests

In the Business Buddy app, the backend server receives requests for chat messages and for storing and retrieving settings values. Each of these operations is performed by calling an endpoint exposed on the server.

In this implementation we use a simple Express server. You're free to use any type of server for your app's backend.

When an app server receives a request to an endpoint, you usually need to:

  • Authenticate that the request is from your app and not a malicious user
  • Know which instance of your app has sent the request

You'll also need to do some CORS setup to make sure your server allows the requests from your app.

CORS

To set up CORS properly, we need to add headers that allow access from certain origins and with certain HTTP methods.

In our case, we whitelist localhost for testing purposes and the URL for our app frontend on the Wix App CDN.

The URL of an app on the CDN is in the following format:

Copy
1
https://<your-app-id>.wix.run

And this is how we whitelist the URLs on our server.

Copy
1
app.use(
2
cors({
3
origin(requestOrigin, callback) {
4
const whitelist = [
5
'http://localhost',
6
'https://1522de8b-ea83-423b-9da0-166fdc7ef372.wix.run',
7
];
8
9
if (
10
requestOrigin &&
11
whitelist.some((whitelistOrigin) =>
12
requestOrigin.includes(whitelistOrigin)
13
)
14
) {
15
callback(null, true);
16
} else {
17
callback(new Error('Not allowed by CORS'));
18
}
19
},
20
})
21
);

Authentication

Now that we've dealt with CORS issues, the next thing to do is to authenticate the requests coming into our server.

To authenticate requests, we first need our app's secret key from the Wix Developers Center. We get the key from the OAuth page in our app's dashboard. Then we add the key to an environment variable named WIX_APP_SECRET.

Now that we have the key, we can write code to authorize the request. In our case, we write this code in a file named utils.ts.


First, we create the authorizeWixRequest() function. This function reads the authorization header sent from our app frontend and checks it using the parseInstance() function described below.

Copy
1
export function authorizeWixRequest(req: express.Request) {
2
const authorization = req.headers.authorization;
3
if (!authorization) throw new Error('No authorization header');
4
const instance = parseInstance(
5
authorization,
6
process.env.WIX_APP_SECRET as string
7
);
8
if (!instance) throw new Error('Invalid instance');
9
return instance;
10
}

Next, we create the parseInstance() function to parse the received app instance and check it against our app's secret key using the validateInstance() function described below.

Copy
1
export function parseInstance(
2
instance: string,
3
appSecret: string
4
): {
5
instanceId: string;
6
appDefId: string;
7
signDate: string;
8
uid: string;
9
permissions: 'OWNER';
10
demoMode: boolean;
11
siteOwnerId: string;
12
siteMemberId: string;
13
expirationDate: string;
14
loginAccountId: string;
15
pai: null;
16
lpai: null;
17
} | null {
18
var parts = instance.split('.'),
19
hash = parts[0],
20
payload = parts[1];
21
22
if (!payload) {
23
return null;
24
}
25
26
if (!validateInstance(hash, payload, appSecret)) {
27
console.log('Provided instance is invalid: ' + instance);
28
return null;
29
}
30
31
return JSON.parse(base64Decode(payload, 'utf8'));
32
}

Then, we create the validateInstance() function to authenticate the instance against our app secret.

Copy
1
function validateInstance(hash: string, payload: string, secret: string) {
2
if (!hash) {
3
return false;
4
}
5
6
hash = base64Decode(hash);
7
8
var signedHash = createHmac('sha256', secret)
9
.update(payload)
10
.digest('base64');
11
12
return hash === signedHash;
13
}

Finally, to use this authentication code, we simply call the authorizeWixRequest() function and pass it an incoming request. For example, when we receive a request for a product chat we authorize the request before continuing.

Copy
1
app.post("/chat/product", async function (req, res) {
2
const { instanceId } = authorizeWixRequest(req);
3
4
// continue to process request...
5
}

Multiple Instances

In the Business Buddy app, the backend server stores settings per app instance. We use the instance ID to associate a particular setting value with a particular instance of our app.

In our app, we do this by storing the instance ID alongside each setting value in a simple key-value store.


You might have noticed that the authorizeWixRequest() function mentioned above returns the parsed instance information, including an instanceId. We can pass that information to the key-value store when we process a request, such as a /settings POST, as you can see here.

Copy
1
app.post('/settings', async function (req, res) {
2
const { instanceId } = authorizeWixRequest(req);
3
const behaviorDirective = req.body.behaviorDirective;
4
saveBehaviorDirective(instanceId, behaviorDirective);
5
res.sendStatus(200);
6
});

Then, in the key-value store, we can store the value of the instanceId as the key and the setting text as the value.

Copy
1
let behaviorDirectives: { [instanceId: string]: string } = {};
2
3
export function saveBehaviorDirective(instanceId: string, directive: string) {
4
behaviorDirectives[instanceId] = directive;
5
}

Up next

Now that you understand how to receive backend request from an app, you've got all the basics you need to know. At this point, feel free to play around with the example app some more, or get started on writing your own awesome app.

Was this helpful?
Yes
No