Skip to content

Commit 8b1f741

Browse files
Paulo Cabralwaldyrious
authored andcommitted
Add authentication sample using PAT
1 parent 48cca5c commit 8b1f741

File tree

8 files changed

+284
-0
lines changed

8 files changed

+284
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Base Url endpoint
2+
BASE_URL = 'https://api-sandbox.uphold.com'
3+
4+
USERNAME = 'my_registration_email@domain.com'
5+
PASSWORD = 'my_password_in_clear_text'
6+
PAT_DESCRIPTION = 'Put a Description Here'
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.env
2+
node_modules/
3+
package-lock.json
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Client credentials PAT
2+
3+
This sample project demonstrates how to authenticate in the Uphold API using a Personal Access Token (PAT).
4+
For further background, please refer to the [API documentation](https://uphold.com/en/developer/api/documentation)
5+
6+
## Summary
7+
8+
**Ideal for scripts**, automated tools and command-line programs which remain under the control of your personal Uphold account.
9+
10+
This sample project performs the following actions:
11+
12+
- Create a new PAT
13+
- List all created PAT's associated to this account
14+
15+
**Important notice:** If the account has two-factor authentication (2FA) active, a one-time-password (OTP) must be passed when creating PATs.
16+
In the Sandbox environment, the special OTP value `000000` can be passed for convenience, as can be seen in the `index.js` file. In production, you would need to use an actual TOTP code provided by your chosen authenticator app (e.g. Google Authenticator).
17+
18+
## Requirements
19+
20+
- `node` v13.14.0 +
21+
22+
## Setup
23+
24+
- run `npm install` (or `yarn install`)
25+
- create a `.env` file based on the `.env.example` file, and populate it with the required data
26+
27+
## Run
28+
29+
- run `node index.js`
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Dependencies.
3+
*/
4+
5+
import axios from "axios";
6+
import b64Pkg from "js-base64";
7+
import dotenv from "dotenv";
8+
import path from "path";
9+
10+
const { encode } = b64Pkg;
11+
dotenv.config({ path: path.resolve() + "/.env" });
12+
13+
/**
14+
* Get list of authentication methods, using basic authentication (username and password).
15+
*/
16+
17+
export async function getAuthenticationMethods() {
18+
// Base64-encoded authentication credentials
19+
const auth = encode(process.env.USERNAME + ":" + process.env.PASSWORD);
20+
21+
// Set GET options for Axios
22+
const options = {
23+
method: "GET",
24+
headers: {
25+
Authorization: "Basic " + auth,
26+
},
27+
url: `${process.env.BASE_URL}/v0/me/authentication_methods`,
28+
};
29+
30+
const data = axios(options)
31+
.then((response) => {
32+
return response.data;
33+
})
34+
.catch((error) => {
35+
error.response.data.errors
36+
? console.log(JSON.stringify(error.response.data.errors, null, 2))
37+
: console.log(JSON.stringify(error, null, 2));
38+
throw error;
39+
});
40+
41+
return data;
42+
}
43+
44+
/**
45+
* Create a Personal Access Token (PAT), using basic authentication (username and password).
46+
* The time-based one-time password (TOTP) parameter
47+
* is typically provided by an OTP application, e.g. Google Authenticator.
48+
*/
49+
50+
export async function createNewPAT(totp) {
51+
// Base64-encoded authentication credentials
52+
const auth = encode(process.env.USERNAME + ":" + process.env.PASSWORD);
53+
54+
let headers = {
55+
"Authorization": "Basic " + auth,
56+
"content-type": "application/json",
57+
};
58+
59+
// Set OTP headers if the totp parameter is passed
60+
const otpHeaders = {
61+
"OTP-Method-Id": totp.OTPMethodId,
62+
"OTP-Token": totp.OTPToken,
63+
};
64+
65+
if (totp.OTPMethodId) {
66+
headers = { ...headers, ...otpHeaders };
67+
}
68+
69+
// Set post options for axios
70+
const options = {
71+
method: "POST",
72+
headers,
73+
data: {
74+
description: process.env.PAT_DESCRIPTION,
75+
},
76+
url: `${process.env.BASE_URL}/v0/me/tokens`,
77+
};
78+
79+
const data = axios(options)
80+
.then((response) => {
81+
return response.data;
82+
})
83+
.catch((error) => {
84+
error.response.data.errors
85+
? console.log(JSON.stringify(error.response.data.errors, null, 2))
86+
: console.log(JSON.stringify(error, null, 2));
87+
throw error;
88+
});
89+
90+
return data;
91+
}
92+
93+
/**
94+
* Get list of Personal Access Tokens (PATs), using a bearer token (client credentials.
95+
*/
96+
97+
export async function getMyPATs(accessToken) {
98+
try {
99+
const r = await axios.get(`${process.env.BASE_URL}/v0/me/tokens`, {
100+
headers: {
101+
Authorization: `Bearer ${accessToken}`,
102+
},
103+
});
104+
return r.data;
105+
} catch (error) {
106+
console.log(JSON.stringify(error, null, 2));
107+
throw error;
108+
}
109+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Dependencies.
3+
*/
4+
5+
import {
6+
createNewPAT,
7+
getAuthenticationMethods,
8+
getMyPATs,
9+
} from "./cc-pat.js";
10+
11+
(async () => {
12+
// Get list of authentication methods
13+
const authMethods = await getAuthenticationMethods();
14+
15+
// In the Sandbox environment, the special OTP value `000000` can be passed for convenience.
16+
const totp = {
17+
OTPMethodId: "",
18+
OTPToken: "000000",
19+
};
20+
21+
// Try to determine if the authenticated account has two-factor authentication (2FA) active,
22+
// as that will require a one-time password (OTP) for the PAT creation request.
23+
const totpCheck =
24+
authMethods != null ? authMethods.find((x) => x.type === "totp") : null;
25+
if (totpCheck) {
26+
totp.OTPMethodId = totpCheck.id;
27+
}
28+
29+
// Create a PAT
30+
const newPAT = await createNewPAT(totp);
31+
32+
if (newPAT.accessToken) {
33+
console.log("New Personal Access Token (PAT) created with success");
34+
console.debug(newPAT.accessToken);
35+
36+
// Use the newly created PAT to list all PATs for this account
37+
console.log("List of available PATs");
38+
console.log(await getMyPATs(newPAT.accessToken));
39+
}
40+
})();

rest-api/javascript/authentication/personal-access-token/package-lock.json

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "uphold-ccp",
3+
"version": "0.0.1",
4+
"description": "Uphold rest Api test client credential PAT example",
5+
"license": "MIT",
6+
"main": "index.js",
7+
"type": "module",
8+
"dependencies": {
9+
"axios": "^0.20.0",
10+
"btoa": "^1.2.1",
11+
"dotenv": "^8.2.0",
12+
"js-base64": "^3.5.2",
13+
"qs": "^6.9.4"
14+
},
15+
"engines": {
16+
"node": ">=13.14"
17+
},
18+
"scripts": {
19+
"run": "node index.js "
20+
}
21+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2+
# yarn lockfile v1
3+
4+
5+
axios@^0.20.0:
6+
version "0.20.0"
7+
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
8+
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
9+
dependencies:
10+
follow-redirects "^1.10.0"
11+
12+
btoa@^1.2.1:
13+
version "1.2.1"
14+
resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73"
15+
integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==
16+
17+
dotenv@^8.2.0:
18+
version "8.2.0"
19+
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
20+
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
21+
22+
follow-redirects@^1.10.0:
23+
version "1.13.0"
24+
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
25+
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
26+
27+
js-base64@^3.5.2:
28+
version "3.5.2"
29+
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.5.2.tgz#3cc800e4f10812b55fb5ec53e7cabaef35dc6d3c"
30+
integrity sha512-VG2qfvV5rEQIVxq9UmAVyWIaOdZGt9M16BLu8vFkyWyhv709Hyg4nKUb5T+Ru+HmAr9RHdF+kQDKAhbJlcdKeQ==
31+
32+
qs@^6.9.4:
33+
version "6.9.4"
34+
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
35+
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==

0 commit comments

Comments
 (0)