Skip to content

Commit

Permalink
chore: add example of passing bearer auth token with setup frame (#287)
Browse files Browse the repository at this point in the history
* chore: add example of passing bearer auth token with setup frame

Signed-off-by: Kevin Viglucci <[email protected]>

* chore: apply linting

Signed-off-by: Kevin Viglucci <[email protected]>

---------

Signed-off-by: Kevin Viglucci <[email protected]>
  • Loading branch information
viglucci authored Oct 15, 2024
1 parent ee00386 commit 93dbba2
Show file tree
Hide file tree
Showing 4 changed files with 514 additions and 56 deletions.
4 changes: 3 additions & 1 deletion packages/rsocket-examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"start-client-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client/example.ts",
"start-client-server-apollo-graphql": "ts-node -r tsconfig-paths/register src/graphql/apollo/client-server/example.ts",
"start-client-server-composite-metadata-auth-example-client": "ts-node -r tsconfig-paths/register src/composite-metadata/bearer-token-auth/client.ts",
"start-client-server-composite-metadata-auth-example-server": "ts-node -r tsconfig-paths/register src/composite-metadata/bearer-token-auth/server.ts"
"start-client-server-composite-metadata-auth-example-server": "ts-node -r tsconfig-paths/register src/composite-metadata/bearer-token-auth/server.ts",
"start-client-server-composite-metadata-auth-setup-frame-example-client": "ts-node -r tsconfig-paths/register src/composite-metadata/bearer-token-auth-setup-frame/client.ts",
"start-client-server-composite-metadata-auth-setup-frame-example-server": "ts-node -r tsconfig-paths/register src/composite-metadata/bearer-token-auth-setup-frame/server.ts"
},
"dependencies": {
"@apollo/client": "^3.5.10",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright 2021-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Payload, RSocket, RSocketConnector } from "rsocket-core";
import { TcpClientTransport } from "rsocket-tcp-client";
import {
encodeBearerAuthMetadata,
encodeCompositeMetadata,
encodeRoute,
WellKnownMimeType,
} from "rsocket-composite-metadata";
import { exit } from "process";
import Logger from "../../shared/logger";
import MESSAGE_RSOCKET_ROUTING = WellKnownMimeType.MESSAGE_RSOCKET_ROUTING;
import MESSAGE_RSOCKET_AUTHENTICATION = WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION;

function makeMetadata(bearerToken?: string, route?: string) {
const map = new Map<WellKnownMimeType, Buffer>();

if (bearerToken) {
map.set(
MESSAGE_RSOCKET_AUTHENTICATION,
encodeBearerAuthMetadata(Buffer.from(bearerToken))
);
}

if (route) {
const encodedRoute = encodeRoute(route);
map.set(MESSAGE_RSOCKET_ROUTING, encodedRoute);
}

return encodeCompositeMetadata(map);
}

function makeConnector(token: string) {
// NOTE: THIS EXAMPLE DOES NOT COVER TLS.
// ALWAYS USE A SECURE CONNECTION SUCH AS TLS WHEN TRANSMITTING SENSITIVE INFORMATION SUCH AS AUTH TOKENS.
return new RSocketConnector({
transport: new TcpClientTransport({
connectionOptions: {
host: "127.0.0.1",
port: 9090,
},
}),
setup: {
payload: {
data: Buffer.from([]),
metadata: makeMetadata(token),
},
},
});
}

async function requestResponse(
rsocket: RSocket,
compositeMetaData: Buffer,
message: string = ""
): Promise<Payload> {
return new Promise((resolve, reject) => {
return rsocket.requestResponse(
{
data: Buffer.from(message),
metadata: compositeMetaData,
},
{
onError: (e) => {
reject(e);
},
onNext: (payload, isComplete) => {
Logger.info(
`onNext payload[data: ${payload.data}; metadata: ${payload.metadata}]|${isComplete}`
);
resolve(payload);
},
onComplete: () => {},
onExtension: () => {},
}
);
});
}

async function main() {
try {
// we expect this connection to fail because we aren't passing a valid token
const connector = makeConnector("");
const rsocket = await connector.connect();
await new Promise(function (resolve, reject) {
Logger.info("Rejecting once socket closes...");
rsocket.onClose((e) => {
reject(e);
});
});
} catch (e) {
Logger.error(`Expected error: ${e}`);
}

// NOTE: YOU SHOULD NEVER HARD CODE AN AUTH TOKEN IN A FILE IN THIS WAY. THIS IS PURELY FOR EXAMPLE PURPOSES.
// The SHA1 HASH of rsocket-js-2024-10
const exampleToken = "8a7d50f76ef86c75bd3563e55f8835515189dbff";

// we expect this connection to succeed because we pass a valid token
const connector = makeConnector(exampleToken);
const rsocket = await connector.connect();

// this request SHOULD pass
const echoResponse = await requestResponse(
rsocket,
makeMetadata(null, "EchoService.echo"),
"Hello World"
);
Logger.info(`EchoService.echo response: ${echoResponse.data.toString()}`);

// this request will reject (unknown route)
try {
await requestResponse(
rsocket,
makeMetadata(null, "UnknownService.unknown"),
"Hello World"
);
} catch (e) {
Logger.error(`Expected error: ${e}`);
}

// this request will reject (no routing data)
try {
await requestResponse(rsocket, makeMetadata(null), "Hello World");
} catch (e) {
Logger.error(`Expected error: ${e}`);
}

const whoAmiResponse = await requestResponse(
rsocket,
makeMetadata(exampleToken, "AuthService.whoAmI")
);
Logger.info(`AuthService.whoAmI response: ${whoAmiResponse.data.toString()}`);
}

main()
.then(() => exit())
.catch((error: Error) => {
Logger.error(error);
setTimeout(() => {
exit(1);
});
});
Loading

0 comments on commit 93dbba2

Please sign in to comment.