Skip to content

Commit 4da28fa

Browse files
authored
feat(chrome-extension): Handle manifest permissions in a more-deterministic fashion (clerk#4133)
1 parent 7c27b0c commit 4da28fa

File tree

95 files changed

+8284
-1198
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+8284
-1198
lines changed

.changeset/afraid-toes-sin.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
'@clerk/clerk-react': patch
4+
---
5+
6+
Include **BUILD_DISABLE_RHC** to allow for builds which remove remotely hosted code as it is a requirement for browser extensions.

.changeset/tidy-garlics-boil.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/chrome-extension': major
3+
---
4+
5+
Consume packages with remotely hosted code removed as required by Manifest v3.

.changeset/wise-spiders-play.md

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
'@clerk/chrome-extension': major
3+
---
4+
5+
#### Permission Updates (BREAKING)
6+
7+
The `storage` entry in `host_permissions` is now required for all extensions.
8+
While it's likely that this is already enabled in your extension, this change is to ensure that Clerk can store the necessary data for the extension to function properly.
9+
10+
**How to Update:** Add the following to your `manifest.json` file:
11+
12+
```json
13+
{
14+
"host_permissions": ["storage"]
15+
}
16+
```
17+
18+
#### Introducing `syncHost` (BREAKING)
19+
20+
In an effort to make the handling of sync hosts more deterministic, we have introduced a new parameter `syncHost` to `<ClerkProvider>`
21+
22+
**How to Update:** Replace `syncSessionWithTab` with `syncHost` in the `<ClerkProvider>` component and set `syncHost` to the host that you intend to synchronize with.
23+
24+
#### Service Workers `createClerkClient`
25+
26+
We've introduced a new method `createClerkClient` to handle background tasks in your extension!
27+
28+
```ts
29+
import { createClerkClient } from '@clerk/chrome-extension/background';
30+
31+
// Create a new Clerk instance and get a fresh token for the user
32+
async function getToken() {
33+
const clerk = await createClerkClient({
34+
publishableKey: process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY,
35+
});
36+
return await clerk.session?.getToken();
37+
}
38+
39+
// Create a listener to listen for messages from content scripts
40+
// NOTE: A runtime listener cannot be async.
41+
// It must return true, in order to keep the connection open and send a response later.
42+
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
43+
// You can use the token in the listener to perform actions on behalf of the user
44+
// OR send the token back to the content script
45+
getToken().then(token => sendResponse({ token }));
46+
return true;
47+
});
48+
```

packages/chrome-extension/README.md

+32-110
Original file line numberDiff line numberDiff line change
@@ -27,134 +27,56 @@
2727

2828
## Getting Started
2929

30-
[Clerk](https://clerk.com/?utm_source=github&utm_medium=clerk_chrome_extension) is the easiest way to add authentication and user management to your Chrome Extension. Add sign up, sign in, and profile management to your application in minutes.
30+
[Clerk](https://clerk.com/?utm_source=github&utm_medium=clerk_chrome_extension) is the easiest way to add authentication and user management to your Browser Extension. Add sign up, sign in, and profile management to your application in minutes.
3131

3232
### Prerequisites
3333

3434
- Node.js `>=18.17.0` or later
3535
- An existing Clerk application. [Create your account for free](https://dashboard.clerk.com/sign-up?utm_source=github&utm_medium=clerk_chrome_extension).
3636
- An existing React app (using [Vite](https://crxjs.dev/vite-plugin/) for example)
3737

38-
### Installation
39-
40-
1. Add `@clerk/chrome-extension` to your project:
41-
42-
```shell
43-
npm install @clerk/chrome-extension
44-
```
45-
46-
1. Retrieve the **Publishable key** from your [Clerk dashboard](https://dashboard.clerk.com/last-active?path=api-keys) and set it as an environment variable. For example, if you used Vite:
47-
48-
```sh
49-
VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxx
50-
```
51-
52-
1. Add `<ClerkProvider>` to your app and define the `routerPush` & `routerReplace` properties. For example, with using `react-router-dom`:
53-
54-
```tsx
55-
// App.tsx
56-
import { SignedIn, SignedOut, SignIn, SignUp, ClerkProvider } from '@clerk/chrome-extension';
57-
import { useNavigate, Routes, Route, MemoryRouter } from 'react-router-dom';
58-
59-
function HelloUser() {
60-
return <p>Hello user</p>;
61-
}
62-
63-
const publishableKey = process.env.VITE_CLERK_PUBLISHABLE_KEY || '';
64-
65-
function ClerkProviderWithRoutes() {
66-
const navigate = useNavigate();
67-
68-
return (
69-
<ClerkProvider
70-
publishableKey={publishableKey}
71-
routerPush={to => navigate(to)}
72-
routerReplace={to => navigate(to, { replace: true })}
73-
>
74-
<Routes>
75-
<Route
76-
path='/sign-up/*'
77-
element={<SignUp signInUrl='/' />}
78-
/>
79-
<Route
80-
path='/'
81-
element={
82-
<>
83-
<SignedIn>
84-
<HelloUser />
85-
</SignedIn>
86-
<SignedOut>
87-
<SignIn
88-
afterSignInUrl='/'
89-
signUpUrl='/sign-up'
90-
/>
91-
</SignedOut>
92-
</>
93-
}
94-
/>
95-
</Routes>
96-
</ClerkProvider>
97-
);
98-
}
99-
100-
function App() {
101-
return (
102-
<MemoryRouter>
103-
<ClerkProviderWithRoutes />
104-
</MemoryRouter>
105-
);
106-
}
107-
108-
export default App;
109-
```
110-
111-
## Usage
112-
113-
Example repositories:
38+
### Feature Support
11439

115-
- [Standalone](https://github.com/clerk/clerk-chrome-extension-starter/tree/main): The extension is using its own authentication
116-
- [WebSSO](https://github.com/clerk/clerk-chrome-extension-starter/tree/webapp_sso): The extensions shares authentication with a website in the same browser
117-
118-
### WebSSO
119-
120-
If you want to use **WebSSO** (extension shares authentication state with a website in same browser) you'll need to add the `syncSessionWithTab` prop to `<ClerkProvider>`.
40+
Please see the latest extension [authentication support matrix](https://clerk.com/docs/references/chrome-extension/overview?utm_source=github&utm_medium=clerk_chrome_extension) in the Clerk documentation for more information.
12141

122-
#### Extension Manifest (`manifest.json`)
42+
### Usage
12343

124-
You must enable the following permissions in your `manifest.json` file:
44+
1. **Installation:** `npm install @clerk/chrome-extension`
45+
2. **Set a consistent extension key**: A browser extension can be identified by its unique key, in a similar way to how a website can be identified by its domain. You will need to explicitly configure your extension's key or it will change often. If the key changes, it can cause the extension to fail. See the [Configure a Consistent Key](https://clerk.com/docs/references/chrome-extension/configure-consistent-crx-id?utm_source=github&utm_medium=clerk_chrome_extension) guide for more information.
46+
3. **Update Clerk Settings**: Once you've set up a consistent extension key, you'll need to configure your Clerk settings to allow the extension to communicate with your Clerk API.
47+
You can do this by adding the extension key to the list of allowed origins in your Clerk settings. Setting the `allowed_origins` is **required** for both **Development** and **Production** instances.
12548

126-
```json
127-
{
128-
"permissions": ["cookies", "storage"]
129-
}
130-
```
49+
```bash
50+
curl -X PATCH https://api.clerk.com/v1/instance \
51+
-H "Content-type: application/json" \
52+
-H "Authorization: Bearer <CLERK_SECRET_KEY>" \
53+
-d '{"allowed_origins": ["chrome-extension://<YOUR_EXTENSION_KEY>"]}'
54+
```
13155

132-
More info on the "cookies" permission: [Google Developer Cookies Reference](https://developer.chrome.com/docs/extensions/reference/cookies/).
133-
More info on the "storage" permission: [Google Developer Storage Reference](https://developer.chrome.com/docs/extensions/reference/storage/).
56+
4. **Set Environment Variables:** Retrieve the **Publishable key** from your [Clerk dashboard](https://dashboard.clerk.com/last-active?path=api-keys&utm_source=github&utm_medium=clerk_chrome_extension) and set it as an environment variable.
13457

135-
#### Host Permissions
58+
```sh
59+
# Vite
60+
VITE_CLERK_PUBLISHABLE_KEY=pk_test_xxx
61+
```
13662

137-
You must enable the following host permissions in your `manifest.json` file:
63+
```sh
64+
# Plasmo
65+
PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxx
66+
```
13867

139-
- **Development:** `"host_permissions": ["http://localhost"]`
140-
- If you're using a domain other than `localhost`, you'll want replace that entry with your domain: `http://<DOMAIN>`
141-
- **Production:** `"host_permissions": ["https://<YOUR_CLERK_FRONTEND_API_GOES_HERE>/"]`
142-
- Your Frontend API URL can be found in [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=api-keys) under the **Show API URLs** option.
68+
5. **Update the extension manifest:** You'll need to update your extension manifest permissions to support Clerk.
69+
1. [**Base configuration**:](/packages/chrome-extension/docs/manifest.md#base-configuration) Use this if you plan to only use Clerk in the context of the extention.
70+
2. [**Session sync configuration**:](/packages/chrome-extension/docs/manifest.md#sync-host-configuration) Use this if you plan to share authentication with a website in the same browser.
71+
6. **Add Clerk to your app:** Though not required, we generally suggest using Plasmo for browser extension development. This will enforce common standards across your extension as well as allow for easier integration with other browsers in the future.
14372
144-
For more info on host permissions visit [Google's developer `host_permissions` reference](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/#host-permissions).
73+
1. [**Via `ClerkProvider`:**](/packages/chrome-extension/docs/clerk-provider.md) This is the general approach to all extensions. From here you'll be able to support extension-only authentication as well as sharing authentication with a website in the same browser.
74+
2. [**Via service workers**:](/packages/chrome-extension/docs/service-workers.md) If you also require the use of background service workers, this will allow you to access the Clerk client from the extension context.
14575

146-
#### Clerk Settings
76+
## Example repositories
14777

148-
Add your Chrome extension origin to your instance's `allowed_origins` using the [Backend API](https://clerk.com/docs/reference/backend-api):
149-
150-
```bash
151-
curl -X PATCH https://api.clerk.com/v1/instance \
152-
-H "Authorization: Bearer sk_secret_key" \
153-
-H "Content-type: application/json" \
154-
-d '{"allowed_origins": ["chrome-extension://extension_id_goes_here"]}'
155-
```
156-
157-
Setting the `allowed_origins` is **required** for both **Development** and **Production** instances.
78+
- [Standalone](https://github.com/clerk/clerk-chrome-extension-starter/tree/main): The extension is using its own authentication
79+
- [WebSSO](https://github.com/clerk/clerk-chrome-extension-starter/tree/webapp_sso): The extensions shares authentication with a website in the same browser
15880

15981
## Support
16082

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Clerk Provider Usage
2+
3+
## Core App
4+
5+
```tsx
6+
// App.tsx
7+
import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/chrome-extension';
8+
9+
function App() {
10+
return (
11+
<>
12+
<header>
13+
<SignedOut>
14+
<SignInButton mode='modal' />
15+
</SignedOut>
16+
<SignedIn>
17+
<UserButton />
18+
</SignedIn>
19+
</header>
20+
<main>
21+
<SignedOut>Please Sign In</SignedOut>
22+
<SignedIn>Welcome!</SignedIn>
23+
</main>
24+
</>
25+
);
26+
}
27+
28+
export default App;
29+
```
30+
31+
## Provider
32+
33+
Though not required, we generally suggest using Plasmo for browser extension development.
34+
This will enforce common standards across your extension as well as allow for easier integration with other browsers in the future.
35+
36+
```tsx
37+
// IndexPopup.tsx
38+
import { ClerkProvider } from '@clerk/chrome-extension';
39+
import App from './App';
40+
41+
const PUBLISHABLE_KEY = process.env.PLASMO_PUBLIC_CLERK_PUBLISHABLE_KEY; // REQUIRED
42+
const SYNC_HOST = process.env.PLASMO_PUBLIC_CLERK_SYNC_HOST; // OPTIONAL
43+
44+
function IndexPopup() {
45+
return (
46+
<ClerkProvider
47+
publishableKey={PUBLISHABLE_KEY}
48+
/* OPTIONAL: If syncHost is set, the extension will attempt to grab credentials from the host provided */
49+
syncHost={SYNC_HOST}
50+
>
51+
<App />
52+
</ClerkProvider>
53+
);
54+
}
55+
56+
export default IndexPopup;
57+
```
58+
59+
## Routing
60+
61+
You can hook into the router of your choice to handle navigation. Here's an example using `react-router-dom`:
62+
63+
```tsx
64+
import { ClerkProvider } from '@clerk/chrome-extension';
65+
import { useNavigate, Routes, Route, MemoryRouter } from 'react-router-dom';
66+
import App from './App';
67+
68+
const publishableKey = process.env.VITE_CLERK_PUBLISHABLE_KEY;
69+
70+
function AppWithRouting() {
71+
const navigate = useNavigate();
72+
73+
return (
74+
<Routes>
75+
<Route
76+
path='/sign-up/*'
77+
element={<SignUp signInUrl='/' />}
78+
/>
79+
<Route
80+
path='/'
81+
element={
82+
<>
83+
<SignedIn>Welcome User!</SignedIn>
84+
<SignedOut>
85+
<SignIn
86+
forceRedirectUrl='/'
87+
signUpUrl='/sign-up'
88+
/>
89+
</SignedOut>
90+
</>
91+
}
92+
/>
93+
</Routes>
94+
);
95+
}
96+
97+
function IndexPopupWithRouting() {
98+
const navigate = useNavigate();
99+
100+
return (
101+
<MemoryRouter>
102+
<ClerkProvider
103+
publishableKey={PUBLISHABLE_KEY}
104+
routerPush={to => navigate(to)}
105+
routerReplace={to => navigate(to, { replace: true })}
106+
>
107+
<AppWithRouting />
108+
</ClerkProvider>
109+
</MemoryRouter>
110+
);
111+
}
112+
113+
export default IndexPopupWithRouting;
114+
```
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Clerk Browser Extension Manifest
2+
3+
## Base Configuration
4+
5+
All Browser Extensions require, at minimum, the following configuration:
6+
7+
### Permissions
8+
9+
```json
10+
{
11+
"permissions": ["storage"]
12+
}
13+
```
14+
15+
More info on the "storage" permission: [Google Developer Storage Reference](https://developer.chrome.com/docs/extensions/reference/storage/).
16+
17+
## Sync Host Configuration
18+
19+
When syncing with a host application, you must enable the following permissions:
20+
21+
### Permissions
22+
23+
```json
24+
{
25+
"permissions": ["cookies", "storage"]
26+
}
27+
```
28+
29+
More info on the "cookies" permission: [Google Developer Cookies Reference](https://developer.chrome.com/docs/extensions/reference/cookies/).
30+
31+
More info on the "storage" permission: [Google Developer Storage Reference](https://developer.chrome.com/docs/extensions/reference/storage/).
32+
33+
### Host Permissions
34+
35+
You must enable the following host permissions in your `manifest.json` file. This will allow the extension to communicate with the host application.
36+
37+
```json
38+
{
39+
"host_permissions": [
40+
"http://localhost/*"
41+
"https://<YOUR_PRODUCTION_APP_DOMAIN>/*",
42+
"https://YOUR_CLERK_DEVELOPMENT_FRONTEND_API.clerk.accounts.dev/*",
43+
"https://<YOUR_CLERK_PRODUCTION_FRONTEND_API>/*"
44+
]
45+
}
46+
```
47+
48+
**Notes:**
49+
50+
- Please make sure to include `/*` at the end of each `host_permission`. Feel free to later scope this down, if your usage sees fit.
51+
- The `YOUR_PRODUCTION_APP_DOMAIN` and `YOUR_CLERK_PRODUCTION_FRONTEND_API` are only required when you're ready to go to production.
52+
53+
Your Frontend API URLs can be found in [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=api-keys) under the **Show API URLs** option.

0 commit comments

Comments
 (0)