@@ -16,53 +16,87 @@ ms.author: kpunjabi
16
16
This sample code demonstrates how to configure OIDC client to validate webhook payload using JWT
17
17
18
18
``` JavaScript
19
- import express from " express" ;
19
+ import { createServer } from " http" ;
20
+ import WebSocket from " ws" ;
20
21
import { JwksClient } from " jwks-rsa" ;
21
22
import { verify } from " jsonwebtoken" ;
22
-
23
- const app = express ();
23
+ import url from " url " ;
24
+
24
25
const port = 3000 ;
25
26
const audience = " ACS resource ID" ;
26
27
const issuer = " https://acscallautomation.communication.azure.com" ;
27
-
28
- app .use (express .json ());
29
-
30
- app .post (" /api/callback" , (req , res ) => {
31
- const token = req? .headers ? .authorization ? .split (" " )[1 ] || " " ;
32
-
33
- if (! token) {
34
- res .sendStatus (401 );
35
-
36
- return ;
37
- }
38
-
39
- try {
28
+ const jwksUri = ` ${ issuer} /calling/keys` ;
29
+
30
+ const server = createServer ();
31
+ const wss = new WebSocket.Server ({ noServer: true });
32
+
33
+ const jwksClient = new JwksClient ({ jwksUri });
34
+
35
+ function verifyToken (token : string ): Promise<any> {
36
+ return new Promise ((resolve , reject ) => {
40
37
verify (
41
38
token,
42
- (header , callback ) => {
43
- const client = new JwksClient ({
44
- jwksUri: " https://acscallautomation.communication.azure.com/calling/keys" ,
45
- });
46
-
47
- client .getSigningKey (header .kid , (err , key ) => {
48
- const signingKey = key? .publicKey || key? .rsaPublicKey ;
49
-
50
- callback (err, signingKey);
39
+ (header , cb ) => {
40
+ jwksClient .getSigningKey (header .kid , (err , key ) => {
41
+ const signingKey = key? .getPublicKey ();
42
+ cb (err, signingKey);
51
43
});
52
44
},
53
- {
54
- audience,
55
- issuer,
56
- algorithms: [" RS256" ],
57
- });
58
- // Your implementation on the callback event
59
- res .sendStatus (200 );
60
- } catch (error) {
61
- res .sendStatus (401 );
45
+ { audience, issuer, algorithms: [" RS256" ] },
46
+ (err , decoded ) => (err ? reject (err) : resolve (decoded))
47
+ );
48
+ });
49
+ }
50
+
51
+ // Upgrade HTTP to WebSocket only if token is valid
52
+ server .on (" upgrade" , async (req , socket , head ) => {
53
+ const tokenHeader = req .headers [" authorization" ];
54
+ const token = tokenHeader? .toString ().split (" " )[1 ];
55
+
56
+ if (! token) {
57
+ socket .write (" HTTP/1.1 401 Unauthorized\r\n\r\n " );
58
+ socket .destroy ();
59
+ return ;
60
+ }
61
+
62
+ try {
63
+ const decoded = await verifyToken (token);
64
+ (req as any).user = decoded;
65
+
66
+ wss .handleUpgrade (req, socket, head, (ws ) => {
67
+ wss .emit (" connection" , ws, req);
68
+ });
69
+ } catch (e) {
70
+ console .error (" WebSocket token validation failed:" , e);
71
+ socket .write (" HTTP/1.1 401 Unauthorized\r\n\r\n " );
72
+ socket .destroy ();
62
73
}
63
74
});
64
-
65
- app .listen (port, () => {
66
- console .log (` Server running on port ${ port} ` );
75
+
76
+ // Handle accepted WebSocket connections
77
+ wss .on (" connection" , async (ws : WebSocket , req ) => {
78
+ const user = (req as any).user ;
79
+ console .log (" Authenticated WebSocket connection from:" , user);
80
+
81
+ await initWebsocket (ws);
82
+ await startConversation ();
83
+
84
+ ws .on (" message" , async (packetData : ArrayBuffer ) => {
85
+ try {
86
+ if (ws .readyState === WebSocket .OPEN ) {
87
+ await processWebsocketMessageAsync (packetData);
88
+ }
89
+ } catch (err) {
90
+ 1. console .error (" WebSocket message error:" , err);
91
+ }
92
+ });
93
+
94
+ ws .on (" close" , () => {
95
+ console .log (" WebSocket connection closed" );
96
+ });
97
+ });
98
+
99
+ server .listen (port, () => {
100
+ console .log (` WebSocket server running on port ${ port} ` );
67
101
});
68
102
` ` `
0 commit comments