Skip to content

Commit

Permalink
support preflight OAuth in embeds (#288)
Browse files Browse the repository at this point in the history
* support preflight auth in embed as an inbetween from auth url redirect and embed code

* whoops

* changeset
  • Loading branch information
mayakoneval authored Oct 25, 2023
1 parent 0d7e9cd commit d4ce484
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/modern-snails-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@apollo/explorer': minor
'@apollo/sandbox': minor
---

Support Explorer preflight OAuth in embeds
4 changes: 4 additions & 0 deletions packages/explorer/src/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,9 @@ export const EXPLORER_LISTENING_FOR_PARTIAL_TOKEN =
'ExplorerListeningForPartialToken';
export const PARTIAL_AUTHENTICATION_TOKEN_RESPONSE =
'PartialAuthenticationTokenResponse';
export const PREFLIGHT_OAUTH_REQUEST = 'PreflightOAuthRequest';
export const PREFLIGHT_OAUTH_PROVIDER_RESPONSE =
'PreflightOAuthProviderResponse';
export const PREFLIGHT_OAUTH_RESPONSE = 'PreflightOAuthResponse';
export const INTROSPECTION_QUERY_WITH_HEADERS = 'IntrospectionQueryWithHeaders';
export const PARENT_LOGOUT_SUCCESS = 'ParentLogoutSuccess';
32 changes: 32 additions & 0 deletions packages/explorer/src/helpers/postMessageRelayHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
EXPLORER_SUBSCRIPTION_REQUEST,
EXPLORER_SUBSCRIPTION_TERMINATION,
EXPLORER_LISTENING_FOR_SCHEMA,
PREFLIGHT_OAUTH_REQUEST,
PREFLIGHT_OAUTH_PROVIDER_RESPONSE,
PREFLIGHT_OAUTH_RESPONSE,
} from './constants';
import MIMEType from 'whatwg-mimetype';
import { readMultipartWebStream } from './readMultipartWebStream';
Expand Down Expand Up @@ -159,9 +162,21 @@ export type OutgoingEmbedMessage =
}
| {
name: typeof PARENT_LOGOUT_SUCCESS;
}
| {
name: typeof PREFLIGHT_OAUTH_RESPONSE;
queryParams: string;
};

export type IncomingEmbedMessage =
| MessageEvent<{
name: typeof PREFLIGHT_OAUTH_REQUEST;
oauthUrl: string;
}>
| MessageEvent<{
name: typeof PREFLIGHT_OAUTH_PROVIDER_RESPONSE;
queryParams: string;
}>
| MessageEvent<{
name: typeof EXPLORER_LISTENING_FOR_HANDSHAKE;
}>
Expand Down Expand Up @@ -504,6 +519,23 @@ export const handleAuthenticationPostMessage = ({
embedUrl: string;
}) => {
const { data } = event;
if (data.name === PREFLIGHT_OAUTH_REQUEST) {
const handleEmbedPostMessage = (event: IncomingEmbedMessage) => {
if (event.data.name === PREFLIGHT_OAUTH_PROVIDER_RESPONSE) {
window.removeEventListener('message', handleEmbedPostMessage);
sendPostMessageToEmbed({
message: {
name: PREFLIGHT_OAUTH_RESPONSE,
queryParams: event.data.queryParams,
},
embeddedIFrameElement,
embedUrl,
});
}
};
window.addEventListener('message', handleEmbedPostMessage);
window.open(data.oauthUrl, undefined, '_blank');
}
// When the embed authenticates, save the partial token in local storage
if (data.name === SET_PARTIAL_AUTHENTICATION_TOKEN_FOR_PARENT) {
const partialEmbedApiKeysString = window.localStorage.getItem(
Expand Down
4 changes: 4 additions & 0 deletions packages/sandbox/src/helpers/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ export const EXPLORER_LISTENING_FOR_PARTIAL_TOKEN =
'ExplorerListeningForPartialToken';
export const PARTIAL_AUTHENTICATION_TOKEN_RESPONSE =
'PartialAuthenticationTokenResponse';
export const PREFLIGHT_OAUTH_REQUEST = 'PreflightOAuthRequest';
export const PREFLIGHT_OAUTH_PROVIDER_RESPONSE =
'PreflightOAuthProviderResponse';
export const PREFLIGHT_OAUTH_RESPONSE = 'PreflightOAuthResponse';
export const INTROSPECTION_QUERY_WITH_HEADERS = 'IntrospectionQueryWithHeaders';
export const PARENT_LOGOUT_SUCCESS = 'ParentLogoutSuccess';
32 changes: 32 additions & 0 deletions packages/sandbox/src/helpers/postMessageRelayHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import {
EXPLORER_SUBSCRIPTION_TERMINATION,
EXPLORER_LISTENING_FOR_SCHEMA,
INTROSPECTION_QUERY_WITH_HEADERS,
PREFLIGHT_OAUTH_REQUEST,
PREFLIGHT_OAUTH_RESPONSE,
PREFLIGHT_OAUTH_PROVIDER_RESPONSE,
} from './constants';
import MIMEType from 'whatwg-mimetype';
import { readMultipartWebStream } from './readMultipartWebStream';
Expand Down Expand Up @@ -168,9 +171,21 @@ export type OutgoingEmbedMessage =
}
| {
name: typeof PARENT_LOGOUT_SUCCESS;
}
| {
name: typeof PREFLIGHT_OAUTH_RESPONSE;
queryParams: string;
};

export type IncomingEmbedMessage =
| MessageEvent<{
name: typeof PREFLIGHT_OAUTH_REQUEST;
oauthUrl: string;
}>
| MessageEvent<{
name: typeof PREFLIGHT_OAUTH_PROVIDER_RESPONSE;
queryParams: string;
}>
| MessageEvent<{
name: typeof EXPLORER_LISTENING_FOR_HANDSHAKE;
}>
Expand Down Expand Up @@ -588,6 +603,23 @@ export const handleAuthenticationPostMessage = ({
embedUrl: string;
}) => {
const { data } = event;
if (data.name === PREFLIGHT_OAUTH_REQUEST) {
const handleEmbedPostMessage = (event: IncomingEmbedMessage) => {
if (event.data.name === PREFLIGHT_OAUTH_PROVIDER_RESPONSE) {
window.removeEventListener('message', handleEmbedPostMessage);
sendPostMessageToEmbed({
message: {
name: PREFLIGHT_OAUTH_RESPONSE,
queryParams: event.data.queryParams,
},
embeddedIFrameElement,
embedUrl,
});
}
};
window.addEventListener('message', handleEmbedPostMessage);
window.open(data.oauthUrl, undefined, '_blank');
}
// When the embed authenticates, save the partial token in local storage
if (data.name === SET_PARTIAL_AUTHENTICATION_TOKEN_FOR_PARENT) {
const partialEmbedApiKeysString = window.localStorage.getItem(
Expand Down

0 comments on commit d4ce484

Please sign in to comment.