Skip to content

Commit ccf3c6f

Browse files
feat: add support for HAWK authentication (hoppscotch#4694)
Co-authored-by: jamesgeorge007 <[email protected]>
1 parent cccd711 commit ccf3c6f

File tree

24 files changed

+709
-50
lines changed

24 files changed

+709
-50
lines changed

packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,24 @@ describe("hopp test [options] <file_path_or_id>", { timeout: 100000 }, () => {
483483

484484
expect(error).toBeTruthy();
485485
});
486+
487+
describe("HAWK Authentication", () => {
488+
test("Correctly generates and attaches authorization headers to the request ", async () => {
489+
const COLL_PATH = getTestJsonFilePath(
490+
"hawk-auth-success-coll.json",
491+
"collection"
492+
);
493+
const ENV_PATH = getTestJsonFilePath(
494+
"hawk-auth-envs.json",
495+
"environment"
496+
);
497+
498+
const args = `test ${COLL_PATH} -e ${ENV_PATH}`;
499+
const { error } = await runCLI(args);
500+
501+
expect(error).toBeNull();
502+
});
503+
});
486504
});
487505

488506
describe("Test `hopp test <file_path_or_id> --delay <delay_in_ms>` command:", () => {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"v": 3,
3+
"name": "HAWK Auth (success state) - collection",
4+
"folders": [],
5+
"requests": [
6+
{
7+
"v": "12",
8+
"id": "cm0dm70cw000687bnxi830zz2",
9+
"auth": {
10+
"authType": "hawk",
11+
"authActive": true,
12+
"authId": "<<id>>",
13+
"authKey": "<<key>>",
14+
"algorithm": "<<algorithm>>",
15+
"includePayloadHash": false,
16+
"user": "<<user>>",
17+
"nonce": "<<nonce>>",
18+
"ext": "<<ext>>",
19+
"app": "<<app>>",
20+
"dlg": "<<dlg>>",
21+
"timestamp": "<<timestamp>>"
22+
},
23+
"body": {
24+
"body": null,
25+
"contentType": null
26+
},
27+
"name": "hawk-auth-headers",
28+
"method": "GET",
29+
"params": [],
30+
"headers": [],
31+
"endpoint": "<<url>>",
32+
"testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});",
33+
"preRequestScript": "",
34+
"responses": {},
35+
"requestVariables": []
36+
}
37+
],
38+
"auth": {
39+
"authType": "inherit",
40+
"authActive": true
41+
},
42+
"headers": []
43+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"v": 1,
3+
"id": "cm0dsn3v70004p4qk3l9b7sjm",
4+
"name": "HAWK Auth - environments",
5+
"variables": [
6+
{
7+
"key": "url",
8+
"value": "https://postman-echo.com/auth/hawk"
9+
},
10+
{
11+
"key": "id",
12+
"value": "dh37fgj492je"
13+
},
14+
{
15+
"key": "key",
16+
"value": "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn"
17+
},
18+
{
19+
"key": "algorithm",
20+
"value": "sha256"
21+
},
22+
{
23+
"key": "user",
24+
"value": ""
25+
},
26+
{
27+
"key": "nonce",
28+
"value": ""
29+
},
30+
{
31+
"key": "ext",
32+
"value": ""
33+
},
34+
{
35+
"key": "app",
36+
"value": ""
37+
},
38+
{
39+
"key": "dlg",
40+
"value": ""
41+
},
42+
{
43+
"key": "timestamp",
44+
"value": ""
45+
}
46+
]
47+
}

packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -485,17 +485,17 @@ export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Worksp
485485
export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] =
486486
[
487487
{
488-
v: 6,
488+
v: 7,
489489
id: "clx1f86hv000010f8szcfya0t",
490490
name: "Multiple child collections with authorization & headers set at each level",
491491
folders: [
492492
{
493-
v: 6,
493+
v: 7,
494494
id: "clx1fjgah000110f8a5bs68gd",
495495
name: "folder-1",
496496
folders: [
497497
{
498-
v: 6,
498+
v: 7,
499499
id: "clx1fjwmm000410f8l1gkkr1a",
500500
name: "folder-11",
501501
folders: [],
@@ -537,7 +537,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
537537
],
538538
},
539539
{
540-
v: 6,
540+
v: 7,
541541
id: "clx1fjyxm000510f8pv90dt43",
542542
name: "folder-12",
543543
folders: [],
@@ -595,7 +595,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
595595
],
596596
},
597597
{
598-
v: 6,
598+
v: 7,
599599
id: "clx1fk1cv000610f88kc3aupy",
600600
name: "folder-13",
601601
folders: [],
@@ -707,12 +707,12 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
707707
],
708708
},
709709
{
710-
v: 6,
710+
v: 7,
711711
id: "clx1fjk9o000210f8j0573pls",
712712
name: "folder-2",
713713
folders: [
714714
{
715-
v: 6,
715+
v: 7,
716716
id: "clx1fk516000710f87sfpw6bo",
717717
name: "folder-21",
718718
folders: [],
@@ -752,7 +752,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
752752
],
753753
},
754754
{
755-
v: 6,
755+
v: 7,
756756
id: "clx1fk72t000810f8gfwkpi5y",
757757
name: "folder-22",
758758
folders: [],
@@ -810,7 +810,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
810810
],
811811
},
812812
{
813-
v: 6,
813+
v: 7,
814814
id: "clx1fk95g000910f8bunhaoo8",
815815
name: "folder-23",
816816
folders: [],
@@ -915,12 +915,12 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
915915
],
916916
},
917917
{
918-
v: 6,
918+
v: 7,
919919
id: "clx1fjmlq000310f86o4d3w2o",
920920
name: "folder-3",
921921
folders: [
922922
{
923-
v: 6,
923+
v: 7,
924924
id: "clx1iwq0p003e10f8u8zg0p85",
925925
name: "folder-31",
926926
folders: [],
@@ -960,7 +960,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
960960
],
961961
},
962962
{
963-
v: 6,
963+
v: 7,
964964
id: "clx1izut7003m10f894ip59zg",
965965
name: "folder-32",
966966
folders: [],
@@ -1018,7 +1018,7 @@ export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: Hopp
10181018
],
10191019
},
10201020
{
1021-
v: 6,
1021+
v: 7,
10221022
id: "clx1j2ka9003q10f8cdbzpgpg",
10231023
name: "folder-33",
10241024
folders: [],

packages/hoppscotch-cli/src/utils/pre-request.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import {
3232
generateDigestAuthHeader,
3333
} from "./auth/digest";
3434

35+
import { calculateHawkHeader } from "@hoppscotch/data";
36+
3537
/**
3638
* Runs pre-request-script runner over given request which extracts set ENVs and
3739
* applies them on current request to generate updated request.
@@ -287,6 +289,44 @@ export async function getEffectiveRESTRequest(
287289
value: authHeaderValue,
288290
description: "",
289291
});
292+
} else if (request.auth.authType === "hawk") {
293+
const { method, endpoint } = request;
294+
295+
const hawkHeader = await calculateHawkHeader({
296+
url: parseTemplateString(endpoint, resolvedVariables), // URL
297+
method: method, // HTTP method
298+
id: parseTemplateString(request.auth.authId, resolvedVariables),
299+
key: parseTemplateString(request.auth.authKey, resolvedVariables),
300+
algorithm: request.auth.algorithm,
301+
302+
// advanced parameters (optional)
303+
includePayloadHash: request.auth.includePayloadHash,
304+
nonce: request.auth.nonce
305+
? parseTemplateString(request.auth.nonce, resolvedVariables)
306+
: undefined,
307+
ext: request.auth.ext
308+
? parseTemplateString(request.auth.ext, resolvedVariables)
309+
: undefined,
310+
app: request.auth.app
311+
? parseTemplateString(request.auth.app, resolvedVariables)
312+
: undefined,
313+
dlg: request.auth.dlg
314+
? parseTemplateString(request.auth.dlg, resolvedVariables)
315+
: undefined,
316+
timestamp: request.auth.timestamp
317+
? parseInt(
318+
parseTemplateString(request.auth.timestamp, resolvedVariables),
319+
10
320+
)
321+
: undefined,
322+
});
323+
324+
effectiveFinalHeaders.push({
325+
active: true,
326+
key: "Authorization",
327+
value: hawkHeader,
328+
description: "",
329+
});
290330
}
291331
}
292332

packages/hoppscotch-common/locales/en.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,8 @@
680680
"localaccess_unsupported": "Current interceptor does not support local access, please consider using Agent, Extension interceptors or the Desktop App"
681681
},
682682
"auth": {
683-
"digest": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Digest Authorization."
683+
"digest": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Digest Authorization.",
684+
"hawk": "Agent interceptor or the Hoppscotch Desktop app are recommended when using Hawk Authorization."
684685
},
685686
"body": {
686687
"binary": "Sending binary data via the current interceptor is not supported yet."

packages/hoppscotch-common/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@shopify/lang-jsonc": "1.0.0",
4949
"@tauri-apps/plugin-store": "2.2.0",
5050
"@types/markdown-it": "14.1.2",
51+
"@types/hawk": "9.0.6",
5152
"@unhead/vue": "1.11.10",
5253
"@urql/core": "5.0.6",
5354
"@urql/devtools": "2.0.3",
@@ -66,6 +67,7 @@
6667
"graphql": "16.9.0",
6768
"graphql-language-service-interface": "2.10.2",
6869
"graphql-tag": "2.12.6",
70+
"hawk": "9.0.2",
6971
"insomnia-importers": "3.6.0",
7072
"io-ts": "2.2.21",
7173
"js-md5": "0.8.3",

packages/hoppscotch-common/src/components/http/Authorization.vue

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@
151151
<div v-if="auth.authType === 'aws-signature'">
152152
<HttpAuthorizationAWSSign v-model="auth" :envs="envs" />
153153
</div>
154+
<div v-if="auth.authType === 'hawk'">
155+
<HttpAuthorizationHAWK v-model="auth" :envs="envs" />
156+
</div>
154157
<div v-if="auth.authType === 'digest'">
155158
<HttpAuthorizationDigest v-model="auth" :envs="envs" />
156159
</div>
@@ -193,6 +196,7 @@ import {
193196
HoppRESTAuth,
194197
HoppRESTAuthAWSSignature,
195198
HoppRESTAuthDigest,
199+
HoppRESTAuthHAWK,
196200
HoppRESTAuthOAuth2,
197201
} from "@hoppscotch/data"
198202
@@ -265,6 +269,15 @@ const selectAWSSignatureAuthType = () => {
265269
}
266270
}
267271
272+
const selectHAWKAuthType = () => {
273+
const { algorithm = "sha256" } = auth.value as HoppRESTAuthHAWK
274+
auth.value = {
275+
...auth.value,
276+
authType: "hawk",
277+
algorithm,
278+
} as HoppRESTAuth
279+
}
280+
268281
const selectDigestAuthType = () => {
269282
const {
270283
username = "",
@@ -318,6 +331,11 @@ const authTypes: AuthType[] = [
318331
label: "AWS Signature",
319332
handler: selectAWSSignatureAuthType,
320333
},
334+
{
335+
key: "hawk",
336+
label: "HAWK",
337+
handler: selectHAWKAuthType,
338+
},
321339
]
322340
323341
const authType = pluckRef(auth, "authType")

packages/hoppscotch-common/src/components/http/authorization/AkamaiEG.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
</div>
7070
<div class="flex flex-1 border-b border-dividerLight">
7171
<SmartEnvInput
72-
v-model="auth.maxBody"
72+
v-model="auth.maxBodySize"
7373
:auto-complete-env="true"
7474
placeholder="Max Body Size"
7575
:envs="envs"

0 commit comments

Comments
 (0)