Skip to content

Commit

Permalink
Implemented the DPoP token exchange
Browse files Browse the repository at this point in the history
This implements the OAuth2 code exchange step: after an auth code has been returned by the IdP through redirection, the client can use the obtained auth code to get an access token. If the request has a DPoP header, the returned token is bound to the DPoP key.
  • Loading branch information
NSeydoux committed Oct 12, 2020
1 parent 4ace8af commit 204f15f
Show file tree
Hide file tree
Showing 9 changed files with 761 additions and 73 deletions.
10 changes: 10 additions & 0 deletions packages/oidc-dpop-client-browser/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions packages/oidc-dpop-client-browser/package.json
Expand Up @@ -29,15 +29,17 @@
"@rollup/plugin-node-resolve": "^9.0.0",
"cross-fetch": "^3.0.6",
"rollup": "^2.15.0",
"rollup-plugin-typescript2": "^0.27.1",
"rollup-plugin-node-polyfills": "^0.2.1"
"rollup-plugin-node-polyfills": "^0.2.1",
"rollup-plugin-typescript2": "^0.27.1"
},
"dependencies": {
"@inrupt/solid-client-authn-core": "^0.2.0",
"@types/form-urlencoded": "^2.0.1",
"@types/jsonwebtoken": "^8.5.0",
"@types/node-jose": "^1.1.5",
"@types/url-parse": "^1.4.3",
"@types/uuid": "^8.3.0",
"form-urlencoded": "^4.2.1",
"jose": "^2.0.2",
"jsonwebtoken": "^8.5.1",
"node-jose": "^2.0.0",
Expand Down
30 changes: 1 addition & 29 deletions packages/oidc-dpop-client-browser/src/dpop/dpop.spec.ts
Expand Up @@ -25,38 +25,10 @@ import { describe, it } from "@jest/globals";
import {
createDpopHeader,
decodeJwt,
generateJwk,
generateJwkForDpop,
generateJwkRsa,
normalizeHttpUriClaim,
signJwt,
} from "./dpop";

describe("generateJwk", () => {
it("can generate a RSA-based JWK", async () => {
const key = await generateJwk("RSA");
expect(key.kty).toEqual("RSA");
});

it("can generate an elliptic curve-based JWK", async () => {
const key = await generateJwk("EC", "P-256");
expect(key.kty).toEqual("EC");
});
});

describe("generateJwkForDpop", () => {
it("generates an elliptic curve-base key, which is a sensible default for DPoP", async () => {
const key = await generateJwkForDpop();
expect(key.kty).toEqual("EC");
});
});

describe("generateJwkRsa", () => {
it("generates an RSA key", async () => {
const key = await generateJwkRsa();
expect(key.kty).toEqual("RSA");
});
});
import { generateJwk, generateJwkForDpop } from "./keyGen";

describe("signJwt/decodeJwt", () => {
it("generates a JWT that can be decoded without signature verification", async () => {
Expand Down
41 changes: 1 addition & 40 deletions packages/oidc-dpop-client-browser/src/dpop/dpop.ts
Expand Up @@ -21,35 +21,10 @@

import URL from "url-parse";
import { JWK } from "node-jose";
import {
BasicParameters,
ECCurve,
JSONWebKey,
JWKECKey,
JWKOctKey,
JWKOKPKey,
JWKRSAKey,
OKPCurve,
} from "jose";
import { JSONWebKey, JWKECKey, JWKOctKey, JWKOKPKey, JWKRSAKey } from "jose";
import JWT, { VerifyOptions } from "jsonwebtoken";
import { v4 } from "uuid";

/**
* Generates a Json Web Key
* @param kty Key type
* @param crvBitlength Curve length (only relevant for elliptic curve algorithms)
* @param parameters
* @hidden
*/
export async function generateJwk(
kty: "EC" | "RSA",
crvBitlength?: ECCurve | OKPCurve | number,
parameters?: BasicParameters
): Promise<JSONWebKey> {
const key = await JWK.createKey(kty, crvBitlength, parameters);
return key.toJSON(true) as JSONWebKey;
}

/**
* Generates a Json Web Token (https://tools.ietf.org/html/rfc7519) containing
* the provided payload and using the signature algorithm specified in the options.
Expand Down Expand Up @@ -148,17 +123,3 @@ export async function createDpopHeader(
}
);
}

/**
* Generates a JSON Web Key suitable to be used to sign HTTP request headers.
*/
export async function generateJwkForDpop(): Promise<JSONWebKey> {
return generateJwk("EC", "P-256", { alg: "ES256" });
}

/**
* Generates a JSON Web Key based on the RSA algorithm
*/
export async function generateJwkRsa(): Promise<JSONWebKey> {
return generateJwk("RSA");
}
50 changes: 50 additions & 0 deletions packages/oidc-dpop-client-browser/src/dpop/keyGen.spec.ts
@@ -0,0 +1,50 @@
/*
* Copyright 2020 Inrupt Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { describe, it } from "@jest/globals";

import { generateJwk, generateJwkForDpop, generateJwkRsa } from "./keyGen";

describe("generateJwk", () => {
it("can generate a RSA-based JWK", async () => {
const key = await generateJwk("RSA");
expect(key.kty).toEqual("RSA");
});

it("can generate an elliptic curve-based JWK", async () => {
const key = await generateJwk("EC", "P-256");
expect(key.kty).toEqual("EC");
});
});

describe("generateJwkForDpop", () => {
it("generates an elliptic curve-base key, which is a sensible default for DPoP", async () => {
const key = await generateJwkForDpop();
expect(key.kty).toEqual("EC");
});
});

describe("generateJwkRsa", () => {
it("generates an RSA key", async () => {
const key = await generateJwkRsa();
expect(key.kty).toEqual("RSA");
});
});
53 changes: 53 additions & 0 deletions packages/oidc-dpop-client-browser/src/dpop/keyGen.ts
@@ -0,0 +1,53 @@
/*
* Copyright 2020 Inrupt Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { JWK } from "node-jose";
import { BasicParameters, ECCurve, JSONWebKey, OKPCurve } from "jose";

/**
* Generates a Json Web Key
* @param kty Key type
* @param crvBitlength Curve length (only relevant for elliptic curve algorithms)
* @param parameters
* @hidden
*/
export async function generateJwk(
kty: "EC" | "RSA",
crvBitlength?: ECCurve | OKPCurve | number,
parameters?: BasicParameters
): Promise<JSONWebKey> {
const key = await JWK.createKey(kty, crvBitlength, parameters);
return key.toJSON(true) as JSONWebKey;
}

/**
* Generates a JSON Web Key suitable to be used to sign HTTP request headers.
*/
export async function generateJwkForDpop(): Promise<JSONWebKey> {
return generateJwk("EC", "P-256", { alg: "ES256" });
}

/**
* Generates a JSON Web Key based on the RSA algorithm
*/
export async function generateJwkRsa(): Promise<JSONWebKey> {
return generateJwk("RSA");
}

0 comments on commit 204f15f

Please sign in to comment.