Skip to content

Commit

Permalink
feat: opaque token length can now be influenced
Browse files Browse the repository at this point in the history
This adds a new `formats.bitsOfOpaqueRandomness` configuration option.
It can be a number or a function returning an integer that tells the
provider the minimum randomness in bits.

resolves #760
  • Loading branch information
panva committed Sep 3, 2020
1 parent 995d2d4 commit f35764f
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 3 deletions.
24 changes: 24 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2288,6 +2288,7 @@ _**default value**_:
{
AccessToken: 'opaque',
ClientCredentials: 'opaque',
bitsOfOpaqueRandomness: 256,
customizers: {
'jwt-ietf': undefined,
jwt: undefined
Expand Down Expand Up @@ -2320,6 +2321,29 @@ Configure `formats`:
```
</details>

### formats.bitsOfOpaqueRandomness

The value should be an integer (or a function returning an integer) and the resulting opaque token length is equal to `Math.ceil(i / Math.log2(n))` where n is the number of symbols in the used alphabet, 64 in our case.



_**default value**_:
```js
256
```
<a id="formats-bits-of-opaque-randomness-to-have-e-g-refresh-tokens-values-longer-than-access-tokens"></a><details><summary>(Click to expand) To have e.g. Refresh Tokens values longer than Access Tokens.
</summary><br>

```js
function bitsOfOpaqueRandomness(ctx, token) {
if (token.kind === 'RefreshToken') {
return 384;
}
return 256;
}
```
</details>

### formats.customizers

Functions used before signing a structured Access Token of a given type, such as a JWT one. Customizing here only changes the structured Access Token, not your storage, introspection or anything else. For such extras use [`extraTokenClaims`](#extratokenclaims) instead.
Expand Down
20 changes: 20 additions & 0 deletions lib/helpers/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,26 @@ function getDefaults() {
* This helper should resolve with a JWS Algorithm string.
*/
tokenSigningAlg,

/*
* formats.bitsOfOpaqueRandomness
*
* description: The value should be an integer (or a function returning an integer) and the
* resulting opaque token length is equal to `Math.ceil(i / Math.log2(n))` where n is the
* number of symbols in the used alphabet, 64 in our case.
*
* example: To have e.g. Refresh Tokens values longer than Access Tokens.
* ```js
* function bitsOfOpaqueRandomness(ctx, token) {
* if (token.kind === 'RefreshToken') {
* return 384;
* }
*
* return 256;
* }
* ```
*/
bitsOfOpaqueRandomness: 256,
AccessToken: 'opaque',
ClientCredentials: 'opaque',

Expand Down
15 changes: 12 additions & 3 deletions lib/models/formats/opaque.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ const nanoid = require('../../helpers/nanoid');
const ctxRef = require('../ctx_ref');

const withExtra = new Set(['AccessToken', 'ClientCredentials']);
const bitsPerSymbol = Math.log2(64);
const tokenLength = (i) => Math.ceil(i / bitsPerSymbol);

module.exports = (provider) => ({
// Default nanoid has a (26+26+10+2 = 64) symbol alphabet (6 bits). So with 6 bits per symbol, and
// 43 symbols => (6*27 = 258) total bits.
generateTokenId() {
return nanoid(43);
let length;
if (this.kind !== 'PushedAuthorizationRequest') {
const bitsOfOpaqueRandomness = instance(provider).configuration('formats.bitsOfOpaqueRandomness');
if (typeof bitsOfOpaqueRandomness === 'function') {
length = tokenLength(bitsOfOpaqueRandomness(ctxRef.get(this), this));
} else {
length = tokenLength(bitsOfOpaqueRandomness);
}
}
return nanoid(length);
},
async getValueAndPayload() {
const now = epochTime();
Expand Down
1 change: 1 addition & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ export interface Configuration {
AccessToken?: AccessTokenFormatFunction | TokenFormat;
ClientCredentials?: ClientCredentialsFormatFunction | TokenFormat;
tokenSigningAlg?: (ctx: KoaContextWithOIDC, token: AccessToken | ClientCredentials) => CanBePromise<AsymmetricSigningAlgorithm>;
bitsOfOpaqueRandomness?: number | ((ctx: KoaContextWithOIDC, token: BaseToken) => number);
customizers?: {
jwt?: (ctx: KoaContextWithOIDC, token: AccessToken | ClientCredentials, parts: JWTStructured) => CanBePromise<JWTStructured>;
'jwt-ietf'?: (ctx: KoaContextWithOIDC, token: AccessToken | ClientCredentials, parts: JWTStructured) => CanBePromise<JWTStructured>;
Expand Down

0 comments on commit f35764f

Please sign in to comment.