Skip to content

Commit a636b1b

Browse files
committed
feat(API-1896): Update "Get your App token" guide JS snippets
1 parent 8de99ae commit a636b1b

File tree

2 files changed

+115
-81
lines changed

2 files changed

+115
-81
lines changed
Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,56 @@
11
```js [activate:NodeJS]
22

3-
params // data from your request handling
4-
storage // your own memory system
5-
6-
// Retrieve GET query params from your own framework / http handler
7-
const { pim_url: pimUrl } = params;
8-
9-
// Retrieve your app's Client ID with your own system
10-
const clientId = storage.get("CLIENT_ID");
11-
12-
// Set the access scopes, take care of the 254 chars max !
13-
const scopes = 'read_products write_products';
14-
15-
// The activate URL should have the pim_url param
16-
if (!pimUrl) {
17-
// Return a Bad request response via your own framework / http server
18-
return response(502, { message: "Bad request" });
3+
import express from 'express';
4+
import crypto from 'crypto';
5+
6+
const app = express();
7+
8+
app.get('/activate', (req, res, next) => {
9+
try {
10+
const clientId = "AKENEO_CLIENT_ID";
11+
const scopes = [
12+
"read_products",
13+
"read_catalog_structure",
14+
"read_channel_settings",
15+
"read_channel_localization",
16+
"read_attribute_options",
17+
"read_catalogs",
18+
"write_catalogs",
19+
"delete_catalogs",
20+
];
21+
const session = req.session;
22+
23+
const pimUrl = req.query.pim_url;
24+
if (!pimUrl) {
25+
throw new Error(
26+
"Can't retrieve PIM url, please restart the authorization process."
27+
);
28+
}
29+
30+
// Create a random state for preventing cross-site request forgery
31+
const state = crypto.randomBytes(64).toString("hex");
32+
33+
// Store in the user session the state and the PIM URL
34+
session.state = state;
35+
session.pim_url = pimUrl;
36+
37+
// Build the parameters for the Authorization Request
38+
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1
39+
const params = new URLSearchParams({
40+
response_type: "code",
41+
client_id: clientId,
42+
scope: scopes.join(" "),
43+
state: state,
44+
});
45+
46+
// Build the url for the Authorization Request using the PIM URL
47+
const authorizeUrl =
48+
pimUrl + "/connect/apps/v1/authorize?" + params.toString();
49+
50+
res.redirect(authorizeUrl);
51+
} catch (err) {
52+
next(err);
53+
}
1954
}
2055

21-
// Store the PIM url value with your own system
22-
storage.set("PIM_URL", pimUrl);
23-
24-
// Set a new security state secret and store the value with your own system
25-
const state = require('crypto').randomBytes(32).toString("hex");
26-
storage.set("APP_STATE", state);
27-
28-
// Construct the PIM authorization url, it will be called on "connect" / "open" button
29-
const redirect_url = `${pimUrl}/connect/apps/v1/authorize` +
30-
`?response_type=code` +
31-
`&client_id=${clientId}` +
32-
`&scope=${scopes}` +
33-
`&state=${state}`
34-
35-
// Set the redirection response with your own framework / http server
36-
return redirect(redirect_url);
37-
3856
```
Lines changed: 64 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,69 @@
11
```js [callback:NodeJS]
22

3-
params // data from your request handling
4-
storage // your own memory system
5-
6-
// Retrieve GET query params from your own framework / http handler
7-
const { code, state } = params;
8-
9-
// Retrieve your app's Client ID with your own logic
10-
const pimUrl = storage.get("PIM_URL");
11-
const appState = storage.get("APP_STATE");
12-
const clientId = storage.get("CLIENT_ID");
13-
const clientSecret = storage.get("CLIENT_SECRET");
14-
15-
// Control the security state integrity previously defined, to avoid attacks
16-
if (state !== appState) {
17-
return response(403,
18-
{
19-
"error": "Forbidden",
20-
"error_description": "State integrity failed",
21-
}
22-
)
23-
}
3+
import express from 'express';
4+
import crypto from 'crypto';
5+
import fetch from 'node-fetch'; // https://www.npmjs.com/package/node-fetch
6+
7+
const app = express();
8+
9+
app.get('/callback', async (req, res, next) => {
10+
try {
11+
const appClientSecret = "CLIENT_SECRET";
12+
const appClientId = "CLIENT_ID";
13+
14+
const session = req.session;
15+
16+
const pimUrl = session.pim_url;
17+
const state = req.query.state;
18+
const authorizationCode = req.query.code;
19+
20+
if (!pimUrl) {
21+
throw new Error(
22+
"Can't retrieve PIM url, please restart the authorization process."
23+
);
24+
}
25+
26+
// We check if the received state is the same as in the session, for security.
27+
if (!state || state != session.state) {
28+
throw new Error("Invalid state");
29+
}
2430

25-
// Generate a new challenge code
26-
// a sha256 concatenation of a code_identifier and the client_secret
27-
const codeIdentifier = require('crypto').randomBytes(32).toString('hex')
28-
const codeChallenge = require('crypto')
29-
.createHash('sha256')
30-
.update(`${codeIdentifier}${clientSecret}`)
31-
.digest('hex')
32-
33-
// Send the payload to the PIM instance, ask for an API Token
34-
fetch
35-
.post(`${storage.get('PIM_URL')}/connect/apps/v1/oauth2/token`, {
36-
code,
37-
grant_type: 'authorization_code',
38-
client_id: clientId,
39-
code_identifier: codeIdentifier,
40-
code_challenge: codeChallenge,
41-
})
42-
.then(({ data }) => {
43-
// Retrieve the fresh token and store it with your own system
44-
const { access_token: accessToken } = data
45-
storage.set('API_TOKEN', accessToken)
46-
redirect('/')
47-
})
48-
.catch((data) => {
49-
// handle error
50-
res.status(400).send(data)
51-
})
31+
if (!authorizationCode) {
32+
throw new Error("Missing authorization code");
33+
}
34+
35+
// Generate code for token request
36+
const codeidentifier = crypto.randomBytes(64).toString("hex");
37+
const codeChallenge = crypto
38+
.createHash("sha256")
39+
.update(codeidentifier + appClientSecret)
40+
.digest("hex");
41+
42+
// Build form data to post
43+
const accessTokenRequestPayload = new URLSearchParams({
44+
grant_type: "authorization_code",
45+
code: authorizationCode,
46+
client_id: appClientId,
47+
code_identifier: codeidentifier,
48+
code_challenge: codeChallenge,
49+
});
50+
51+
// Make an authenticated call to the API
52+
const accessTokenUrl = pimUrl + "/connect/apps/v1/oauth2/token";
53+
const response = await fetch(accessTokenUrl, {
54+
method: "post",
55+
body: accessTokenRequestPayload,
56+
headers: {"Content-Type": "application/x-www-form-urlencoded"},
57+
});
58+
59+
const result = await response.json();
60+
61+
const accessToken = result.access_token;
62+
63+
console.log(accessToken);
64+
} catch (err) {
65+
next(err);
66+
}
67+
}
5268

5369
```

0 commit comments

Comments
 (0)