Skip to content

Commit 5eda0b8

Browse files
committed
chore: added expiry to jwt
chore: added stricter types fix: rpc manifest
1 parent 01f7596 commit 5eda0b8

File tree

8 files changed

+52
-40
lines changed

8 files changed

+52
-40
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { HandlerTypes } from '@matrixai/rpc';
2+
import type AuthIdentityToken from '../handlers/AuthIdentityToken.js';
3+
import { UnaryCaller } from '@matrixai/rpc';
4+
5+
type CallerTypes = HandlerTypes<AuthIdentityToken>;
6+
7+
const authIdentityToken = new UnaryCaller<
8+
CallerTypes['input'],
9+
CallerTypes['output']
10+
>();
11+
12+
export default authIdentityToken;

src/client/callers/authSignToken.ts

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/client/callers/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import agentStop from './agentStop.js';
44
import agentUnlock from './agentUnlock.js';
55
import auditEventsGet from './auditEventsGet.js';
66
import auditMetricGet from './auditMetricGet.js';
7-
import authSignToken from './authSignToken.js';
7+
import authIdentityToken from './authIdentityToken.js';
88
import gestaltsActionsGetByIdentity from './gestaltsActionsGetByIdentity.js';
99
import gestaltsActionsGetByNode from './gestaltsActionsGetByNode.js';
1010
import gestaltsActionsSetByIdentity from './gestaltsActionsSetByIdentity.js';
@@ -86,7 +86,7 @@ const clientManifest = {
8686
agentUnlock,
8787
auditEventsGet,
8888
auditMetricGet,
89-
authSignToken,
89+
authIdentityToken,
9090
gestaltsActionsGetByIdentity,
9191
gestaltsActionsGetByNode,
9292
gestaltsActionsSetByIdentity,
@@ -167,7 +167,7 @@ export {
167167
agentStop,
168168
agentUnlock,
169169
auditEventsGet,
170-
authSignToken,
170+
authIdentityToken,
171171
gestaltsActionsGetByIdentity,
172172
gestaltsActionsGetByNode,
173173
gestaltsActionsSetByIdentity,

src/client/errors.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ class ErrorClientProtocolError<T> extends ErrorClient<T> {
2828
exitCode = sysexits.USAGE;
2929
}
3030

31+
class ErrorClientAuthenticationInvalidJTI<T> extends ErrorClient<T> {
32+
static description = 'Failed to generate JTI';
33+
exitCode = sysexits.PROTOCOL;
34+
}
35+
3136
class ErrorClientService<T> extends ErrorClient<T> {}
3237

3338
class ErrorClientServiceRunning<T> extends ErrorClientService<T> {
@@ -50,22 +55,17 @@ class ErrorClientVerificationFailed<T> extends ErrorClientService<T> {
5055
exitCode = sysexits.USAGE;
5156
}
5257

53-
class ErrorClientAuthenticationInvalidToken<T> extends ErrorClient<T> {
54-
static description = 'Token is invalid';
55-
exitCode = sysexits.PROTOCOL;
56-
}
57-
5858
export {
5959
ErrorClient,
6060
ErrorClientAuthMissing,
6161
ErrorClientAuthFormat,
6262
ErrorClientAuthDenied,
6363
ErrorClientInvalidHeader,
6464
ErrorClientProtocolError,
65+
ErrorClientAuthenticationInvalidJTI,
6566
ErrorClientService,
6667
ErrorClientServiceRunning,
6768
ErrorClientServiceNotRunning,
6869
ErrorClientServiceDestroyed,
6970
ErrorClientVerificationFailed,
70-
ErrorClientAuthenticationInvalidToken,
7171
};
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import type {
55
TokenIdentityResponse,
66
} from '../types.js';
77
import type KeyRing from '../../keys/KeyRing.js';
8+
import { IdSortable } from '@matrixai/id';
89
import { UnaryHandler } from '@matrixai/rpc';
910
import Token from '../../tokens/Token.js';
1011
import * as nodesUtils from '../../nodes/utils.js';
12+
import * as clientErrors from '../errors.js';
1113

12-
class AuthSignToken extends UnaryHandler<
14+
class AuthIdentityToken extends UnaryHandler<
1315
{
1416
keyRing: KeyRing;
1517
},
@@ -18,13 +20,19 @@ class AuthSignToken extends UnaryHandler<
1820
> {
1921
public handle = async (): Promise<TokenIdentityResponse> => {
2022
const { keyRing }: { keyRing: KeyRing } = this.container;
21-
const tokenPayload: IdentityResponseData = {
22-
nodeId: nodesUtils.encodeNodeId(keyRing.getNodeId()),
23-
};
24-
const outgoingToken = Token.fromPayload<IdentityResponseData>(tokenPayload);
23+
const idGen = new IdSortable();
24+
const jti = idGen.next().value;
25+
if (jti == null) {
26+
throw new clientErrors.ErrorClientAuthenticationInvalidJTI();
27+
}
28+
const outgoingToken = Token.fromPayload<IdentityResponseData>({
29+
jti: jti.toMultibase('base64'),
30+
exp: Math.floor(Date.now() / 1000) + 60, // 60 seconds after issuing
31+
iss: nodesUtils.encodeNodeId(keyRing.getNodeId()),
32+
});
2533
outgoingToken.signWithPrivateKey(keyRing.keyPair);
2634
return outgoingToken.toEncoded();
2735
};
2836
}
2937

30-
export default AuthSignToken;
38+
export default AuthIdentityToken;

src/client/handlers/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import AgentStop from './AgentStop.js';
2222
import AgentUnlock from './AgentUnlock.js';
2323
import AuditEventsGet from './AuditEventsGet.js';
2424
import AuditMetricGet from './AuditMetricGet.js';
25-
import AuthSignToken from './AuthSignToken.js';
25+
import AuthIdentityToken from './AuthIdentityToken.js';
2626
import GestaltsActionsGetByIdentity from './GestaltsActionsGetByIdentity.js';
2727
import GestaltsActionsGetByNode from './GestaltsActionsGetByNode.js';
2828
import GestaltsActionsSetByIdentity from './GestaltsActionsSetByIdentity.js';
@@ -123,7 +123,7 @@ const serverManifest = (container: {
123123
agentUnlock: new AgentUnlock(container),
124124
auditEventsGet: new AuditEventsGet(container),
125125
auditMetricGet: new AuditMetricGet(container),
126-
authSignToken: new AuthSignToken(container),
126+
authIdentityToken: new AuthIdentityToken(container),
127127
gestaltsActionsGetByIdentity: new GestaltsActionsGetByIdentity(container),
128128
gestaltsActionsGetByNode: new GestaltsActionsGetByNode(container),
129129
gestaltsActionsSetByIdentity: new GestaltsActionsSetByIdentity(container),
@@ -210,7 +210,7 @@ export {
210210
AgentUnlock,
211211
AuditEventsGet,
212212
AuditMetricGet,
213-
AuthSignToken,
213+
AuthIdentityToken,
214214
GestaltsActionsGetByIdentity,
215215
GestaltsActionsGetByNode,
216216
GestaltsActionsSetByIdentity,

src/client/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ type TokenMessage = {
109109
};
110110

111111
type IdentityResponseData = TokenPayload & {
112-
nodeId: NodeIdEncoded;
112+
jti: string;
113+
exp: number;
114+
iss: NodeIdEncoded;
113115
};
114116

115117
type TokenIdentityResponse = SignedTokenEncoded;

tests/client/handlers/auth.test.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ import Logger, { formatting, LogLevel, StreamHandler } from '@matrixai/logger';
77
import { RPCClient } from '@matrixai/rpc';
88
import { WebSocketClient } from '@matrixai/ws';
99
import * as testsUtils from '../../utils/index.js';
10-
import { AuthSignToken } from '#client/handlers/index.js';
11-
import { authSignToken } from '#client/callers/index.js';
10+
import { AuthIdentityToken } from '#client/handlers/index.js';
11+
import { authIdentityToken } from '#client/callers/index.js';
1212
import KeyRing from '#keys/KeyRing.js';
1313
import Token from '#tokens/Token.js';
1414
import ClientService from '#client/ClientService.js';
1515
import * as keysUtils from '#keys/utils/index.js';
1616
import * as networkUtils from '#network/utils.js';
1717
import * as nodesUtils from '#nodes/utils.js';
1818

19-
describe('authSignToken', () => {
20-
const logger = new Logger('authSignToken test', LogLevel.WARN, [
19+
describe('authIdentityToken', () => {
20+
const logger = new Logger('authIdentityToken test', LogLevel.WARN, [
2121
new StreamHandler(
2222
formatting.format`${formatting.level}:${formatting.keys}:${formatting.msg}`,
2323
),
@@ -30,7 +30,7 @@ describe('authSignToken', () => {
3030
let clientService: ClientService;
3131
let webSocketClient: WebSocketClient;
3232
let rpcClient: RPCClient<{
33-
authSignToken: typeof authSignToken;
33+
authIdentityToken: typeof authIdentityToken;
3434
}>;
3535

3636
beforeEach(async () => {
@@ -53,7 +53,7 @@ describe('authSignToken', () => {
5353
});
5454
await clientService.start({
5555
manifest: {
56-
authSignToken: new AuthSignToken({
56+
authIdentityToken: new AuthIdentityToken({
5757
keyRing,
5858
}),
5959
},
@@ -69,7 +69,7 @@ describe('authSignToken', () => {
6969
});
7070
rpcClient = new RPCClient({
7171
manifest: {
72-
authSignToken,
72+
authIdentityToken,
7373
},
7474
streamFactory: () => webSocketClient.connection.newStream(),
7575
toError: networkUtils.toError,
@@ -89,11 +89,13 @@ describe('authSignToken', () => {
8989
});
9090

9191
test('should return a signed token', async () => {
92-
const identityToken = await rpcClient.methods.authSignToken({});
92+
const identityToken = await rpcClient.methods.authIdentityToken({});
9393
const decodedToken = Token.fromEncoded<IdentityResponseData>(identityToken);
9494
const decodedPublicKey = keysUtils.publicKeyFromNodeId(keyRing.getNodeId());
9595
expect(decodedToken.verifyWithPublicKey(decodedPublicKey)).toBeTrue();
9696
const encodedNodeId = nodesUtils.encodeNodeId(keyRing.getNodeId());
97-
expect(decodedToken.payload.nodeId).toBe(encodedNodeId);
97+
expect(decodedToken.payload.iss).toBe(encodedNodeId);
98+
expect(decodedToken.payload.exp).toBeDefined();
99+
expect(decodedToken.payload.jti).toBeDefined();
98100
});
99101
});

0 commit comments

Comments
 (0)