Skip to content

Commit e6c6652

Browse files
committed
update
1 parent 8851bd7 commit e6c6652

5 files changed

Lines changed: 103 additions & 3 deletions

File tree

examples/slack-connect-example/.env.sample

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@ NEXT_PUBLIC_SLACK_CLIENT_ID=<slack client id>
2121
NEXT_PUBLIC_KNOCK_SLACK_CHANNEL_ID=<knock slack channel id>
2222
NEXT_PUBLIC_REDIRECT_URL=http://localhost:3000/
2323

24+
# MS Teams configuration (optional — enables side-by-side testing with Slack)
25+
NEXT_PUBLIC_GRAPH_API_CLIENT_ID=<graph api client id>
26+
NEXT_PUBLIC_KNOCK_MS_TEAMS_CHANNEL_ID=<knock ms teams channel id>
27+
2428
NEXT_PUBLIC_KNOCK_BRANCH=<optional>

examples/slack-connect-example/pages/api/set_token.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ export default async function handler(
1414

1515
const { tenant, user, slackChannelsRecipientObject } = req.body;
1616
try {
17-
const signingKey = process.env.KNOCK_SIGNING_KEY!;
17+
const rawKey = process.env.KNOCK_SIGNING_KEY!;
18+
const signingKey = rawKey.startsWith("LS0t")
19+
? Buffer.from(rawKey, "base64").toString("utf-8")
20+
: rawKey;
1821

1922
// JWT NumericDates specified in seconds:
2023
const currentTime = Math.floor(Date.now() / 1000);
@@ -30,6 +33,7 @@ export default async function handler(
3033
grants: {
3134
[`https://api.knock.app/v1/objects/$tenants/${tenant}`]: {
3235
"slack/channels_read": [{}],
36+
"ms_teams/channels_read": [{}],
3337
},
3438
[`https://api.knock.app/v1/objects/${slackChannelsRecipientObject.collection}/${slackChannelsRecipientObject.objectId}`]:
3539
{

examples/slack-connect-example/pages/index.tsx

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import {
2+
KnockMsTeamsProvider,
23
KnockProvider,
34
KnockSlackProvider,
5+
MsTeamsAuthButton,
46
SlackAuthButton,
57
SlackAuthContainer,
68
SlackChannelCombobox,
@@ -26,10 +28,14 @@ export default function Home() {
2628
collection: process.env.NEXT_PUBLIC_CONNECTIONS_COLLECTION!,
2729
};
2830

29-
const onAuthComplete = (result: string) => {
31+
const onSlackAuthComplete = (result: string) => {
3032
console.log("Result from Slack authentication:", result);
3133
};
3234

35+
const onTeamsAuthComplete = (result: string) => {
36+
console.log("Result from MS Teams authentication:", result);
37+
};
38+
3339
const { isLoading, isError } = useSetToken({
3440
tenant,
3541
user,
@@ -114,7 +120,7 @@ export default function Home() {
114120
<SlackAuthButton
115121
slackClientId={process.env.NEXT_PUBLIC_SLACK_CLIENT_ID!}
116122
redirectUrl={redirectUrl}
117-
onAuthenticationComplete={onAuthComplete}
123+
onAuthenticationComplete={onSlackAuthComplete}
118124
additionalScopes={["users:read", "users:read.email"]}
119125
/>
120126
</div>
@@ -146,6 +152,43 @@ export default function Home() {
146152
</div>
147153
</>
148154
</KnockSlackProvider>
155+
156+
{/* MS Teams provider rendered as sibling to reproduce KNO-13032 */}
157+
{process.env.NEXT_PUBLIC_KNOCK_MS_TEAMS_CHANNEL_ID && (
158+
<KnockMsTeamsProvider
159+
knockMsTeamsChannelId={
160+
process.env.NEXT_PUBLIC_KNOCK_MS_TEAMS_CHANNEL_ID
161+
}
162+
tenantId={tenant}
163+
>
164+
<div
165+
style={{
166+
marginTop: "60px",
167+
borderTop: "2px solid #eee",
168+
paddingTop: "20px",
169+
}}
170+
>
171+
<div
172+
style={{
173+
marginBottom: "20px",
174+
fontFamily: "monospace",
175+
fontSize: "40px",
176+
}}
177+
>
178+
MS Teams connector
179+
</div>
180+
<div style={{ margin: "10px", padding: "10px" }}>
181+
<MsTeamsAuthButton
182+
graphApiClientId={
183+
process.env.NEXT_PUBLIC_GRAPH_API_CLIENT_ID!
184+
}
185+
redirectUrl={redirectUrl}
186+
onAuthenticationComplete={onTeamsAuthComplete}
187+
/>
188+
</div>
189+
</div>
190+
</KnockMsTeamsProvider>
191+
)}
149192
</KnockProvider>
150193
);
151194
}

packages/react-core/src/modules/core/hooks/useAuthPostMessageListener.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ export function useAuthPostMessageListener(
8484
return;
8585
}
8686

87+
// Ignore messages when this integration hasn't opened a popup
88+
if (!popupWindowRef.current || popupWindowRef.current.closed) {
89+
return;
90+
}
91+
8792
const messageType = getMessageType(event.data);
8893

8994
if (messageType === "authComplete") {

packages/react-core/test/core/hooks/useAuthPostMessageListener.test.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,50 @@ describe("useAuthPostMessageListener", () => {
132132
expect(popupWindowRef.current).toBeNull();
133133
});
134134

135+
it("should ignore messages when popupWindowRef is null", () => {
136+
popupWindowRef.current = null;
137+
138+
renderHook(() =>
139+
useAuthPostMessageListener({
140+
knockHost,
141+
popupWindowRef,
142+
setConnectionStatus,
143+
onAuthenticationComplete,
144+
}),
145+
);
146+
147+
const event = new MessageEvent("message", {
148+
data: "authComplete",
149+
origin: knockHost,
150+
});
151+
window.dispatchEvent(event);
152+
153+
expect(setConnectionStatus).not.toHaveBeenCalled();
154+
expect(onAuthenticationComplete).not.toHaveBeenCalled();
155+
});
156+
157+
it("should ignore messages when popup is closed", () => {
158+
mockPopup.closed = true;
159+
160+
renderHook(() =>
161+
useAuthPostMessageListener({
162+
knockHost,
163+
popupWindowRef,
164+
setConnectionStatus,
165+
onAuthenticationComplete,
166+
}),
167+
);
168+
169+
const event = new MessageEvent("message", {
170+
data: "authComplete",
171+
origin: knockHost,
172+
});
173+
window.dispatchEvent(event);
174+
175+
expect(setConnectionStatus).not.toHaveBeenCalled();
176+
expect(onAuthenticationComplete).not.toHaveBeenCalled();
177+
});
178+
135179
it("should ignore messages from different origins", () => {
136180
renderHook(() =>
137181
useAuthPostMessageListener({

0 commit comments

Comments
 (0)