Skip to content

Commit

Permalink
perform handshake from a content script rather than with scripting
Browse files Browse the repository at this point in the history
In this commit, we remove the need for the background script to inject a
function, and instead place a content script on every page the extension
is active that the background script connects to in order to begin the flow.

Here is a diagram of the flow now:

1. Background              2. Content Script     3. Content Script       4. SSO
                              (current tab)         (callback url)

tabs.connect(...)   ------>   Create iFrame  -------------┐
                                                          |
runtime.onConnect(...)  <---------------------    runtime.connect(...)
     |                   Asks for /authorize url
     |
postMessage(...)  ----------------------------->  onMessage(...) ------> iframe
                                                                           |
                                                                           |
disconnect() <---------------------------------   postMessage(...) --------┘
                      Code & State

We also remove the need for the end user to add any code to (3),
since by setting the new content script to be injected in all frames, it
will also be injectend into the new iFrame that is created by (2). This
also nicely matches with where the user of this library will need to get
authentication tokens, as if they are performing an operation from a
content script, then it will mean we will be able to grab a token from
the same page that the user is currently active on which we are
guaranteed to have access to.
  • Loading branch information
pjhul committed Jan 23, 2022
1 parent 959cd96 commit ff486cd
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 166 deletions.
52 changes: 13 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,31 @@ Using [yarn](https://yarnpkg.com)
yarn add auth0-web-extension@https://github.com/pjhul/auth0-web-extension
```

## Getting Started
## Create the token handler

To start, go to Auth0 and add the following URLs under these settings in your application:

- **Allowed Callback URLs**: `chrome-extension://<YOUR_EXTENSION_ID>/callback.html`
- **Allowed Web Origins**: `chrome-extension://<YOUR_EXTENSION_ID>/callback.html`

## Create the callback page

Create a new js file in your project called callback.js with the following contents:
Create a new js file in your project called handler.js with the following contents:

```js
import { handleTokenRequest } from "auth0-web-extension"
handleTokenRequest();
handleTokenRequest(<YOUR_REDIRECT_URI>);
```

**Make sure this file is built and output into its own separate chunk, e.g. build/js/callback.js**

In your build/output folder for your extension (wherever your index.html is located) create a new file called callback.html with the following contents

```html
<html>
<head>
<script src="<PATH_TO_CALLBACK_JS>"></script>
</head>

<body></body>
</html>
```

Here, replace `PATH_TO_CALLBACK_JS` with wherever your callback.js file is output to in your build folder.

## Permissions

In your manifest, you will need to change a couple items:
In your manifest, you will need to add a couple items. It is important to make sure that this new content script gets injected on all the same pages your current content scripts do.

```jsonc
{
/* ... */
"permissions": [
"scripting" // Add the following permission
],
"host_permissions": [
"https://*/*" // Add the following host permissions
],
"web_accessible_resources": [
/* Add the following web accessible resource */
"content_scripts": [
{
"resources": ["callback.html"],
"matches": ["https://*/*"]
"matches": [
"<YOUR_REDIRECT_URI>" // Make sure your redirect url is included
],
"all_frames": true, // All frames must be set to true
"js": ["...", "<PATH_TO_HANDLER_JS>"] // This should be the path to the build output of the file (handler.js) we created in the last step
}
]
}
Expand All @@ -79,7 +54,7 @@ import createAuth0Client from "auth0-web-extension"
const auth0 = createAuth0Client({
domain: '<AUTH0_DOMAIN>',
client_id: '<AUTH0_CLIENT_ID>',
redirect_uri: 'chrome-extension://<YOUR_EXTENSION_ID>/callback.html',
redirect_uri: '<YOUR_REDIRECT_URI>',
});
```

Expand All @@ -93,9 +68,8 @@ const token = await auth0.getTokenSilently(options);

## Caveats

1. This currently only works with callback URLs of the form `chrome-extension://...`, but this limitation will be removed within the next couple days
2. We don't yet support refresh tokens, but again this should be coming soon.
3. This package is not on npm yet, but after some of these other caveats are fixed I'll make it available.
1. We don't yet support refresh tokens, but again this should be coming soon.
2. This package is not on npm yet, but after some of these other caveats are fixed I'll make it available.

## Support + Feedback

Expand Down
136 changes: 66 additions & 70 deletions dist/auth0-web-extension.production.esm.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/auth0-web-extension.production.esm.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/types/handler.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export declare function handleTokenRequest(): Promise<void>;
export declare function handleTokenRequest(redirectUri: string): void;
63 changes: 27 additions & 36 deletions src/Auth0Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
AuthorizeOptions,
GetTokenSilentlyOptions,
GetTokenSilentlyResult,
OAuthTokenOptions,
AuthenticationResult,
} from "./global"

Expand Down Expand Up @@ -179,8 +178,7 @@ export default class Auth0Client {
stateIn,
nonceIn,
code_challenge,
options.redirect_uri ||
this.options.redirect_uri,
options.redirect_uri || this.options.redirect_uri,
);

// TODO: Add support for organizations
Expand All @@ -189,7 +187,7 @@ export default class Auth0Client {
...params,
prompt: "none",
response_mode: "web_message",
})
});

const timeout =
options.timeoutInSeconds || this.options.authorizeTimeoutInSeconds;
Expand All @@ -198,40 +196,33 @@ export default class Auth0Client {
const queryOptions = { active: true, currentWindow: true };
let [currentTab] = await browser.tabs.query(queryOptions);

if(!currentTab?.id) {
throw "Could not access current tab. Do you have the 'activeTab' permission in your manifest?";
}
const codeResult: AuthenticationResult = await new Promise((resolve, reject) => {
if(!currentTab?.id) {
throw "Could not access current tab. Do you have the 'activeTab' permission in your manifest?";
}

await browser.scripting.executeScript({
target: { tabId: currentTab.id, },
func: (url: string) => {
const iframe = document.createElement("iframe");
const parentPort = browser.tabs.connect(currentTab.id, { name: "parent" });

iframe.setAttribute("width", "0");
iframe.setAttribute("height", "0");
iframe.style.display = "none";
const handler = (childPort: browser.Runtime.Port) => {
childPort.onMessage.addListener(message => {
resolve(message);
childPort.disconnect();
parentPort.disconnect();

document.body.appendChild(iframe)
iframe.setAttribute("src", url)
},
args: [params.redirect_uri],
});
browser.runtime.onConnect.removeListener(handler);
});

childPort.postMessage({
authorizeUrl: url,
domainUrl: this.domainUrl,
});
}

const codeResult: AuthenticationResult = await new Promise((resolve) => {
browser.runtime.onConnect.addListener((port) => {
port.onMessage.addListener((message, port) => {
// TODO: Verify sender
if(message === "auth_params") {
port.postMessage({
authorizeUrl: url,
domainUrl: this.domainUrl,
});
} else {
resolve(message);
port.disconnect();
}
})
})
browser.runtime.onConnect.addListener(handler)

parentPort.postMessage({
redirectUri: params.redirect_uri,
});
});

if(stateIn !== codeResult.state) {
Expand All @@ -240,8 +231,8 @@ export default class Auth0Client {

const {
scope,
audience,
redirect_uri,
audience,
ignoreCache,
timeoutInSeconds,
detailedResponse,
Expand Down Expand Up @@ -356,4 +347,4 @@ const getCustomInitialOptions = (
...customParams
} = options;
return customParams;
};
}
Loading

0 comments on commit ff486cd

Please sign in to comment.