Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/silent-insects-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@clerk/clerk-js': minor
'@clerk/shared': minor
'@clerk/clerk-react': minor
'@clerk/types': minor
---

Added support for authentication with Base
4 changes: 2 additions & 2 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "631KB" },
{ "path": "./dist/clerk.js", "maxSize": "818KB" },
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. @base-org/account is pretty massive

{ "path": "./dist/clerk.browser.js", "maxSize": "78KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "120KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "61KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "117.1KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "118KB" },
{ "path": "./dist/vendors*.js", "maxSize": "43.78KB" },
{ "path": "./dist/vendors*.js", "maxSize": "45KB" },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jacekradko Is this expected ? Maybe something belongs to baseAccountSDKVendor ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can dig into it, but yeah it's gotta be another transitive dependency of a transitive dependency type of thing 😂

{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
{ "path": "./dist/stripe-vendors*.js", "maxSize": "1KB" },
{ "path": "./dist/createorganization*.js", "maxSize": "5KB" },
Expand Down
1 change: 1 addition & 0 deletions packages/clerk-js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
},
"browserslist": "last 2 years",
"dependencies": {
"@base-org/account": "2.0.1",
"@clerk/localizations": "workspace:^",
"@clerk/shared": "workspace:^",
"@clerk/types": "workspace:^",
Expand Down
5 changes: 5 additions & 0 deletions packages/clerk-js/rspack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ const common = ({ mode, variant, disableRHC = false }) => {
name: 'zxcvbn-common',
chunks: 'all',
},
baseAccountSDKVendor: {
test: /[\\/]node_modules[\\/](@base-org\/account|@noble\/curves|abitype|ox|preact|eventemitter3|viem|zustand)[\\/]/,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed to avoid bundling @base-org/account transitive dependencies in our main vendor chunks

name: 'base-account-sdk',
chunks: 'all',
},
coinbaseWalletSDKVendor: {
test: /[\\/]node_modules[\\/](@coinbase\/wallet-sdk|preact|eventemitter3|@noble\/hashes)[\\/]/,
name: 'coinbase-wallet-sdk',
Expand Down
31 changes: 25 additions & 6 deletions packages/clerk-js/src/core/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import type {
__internal_UserVerificationModalProps,
APIKeysNamespace,
APIKeysProps,
AuthenticateWithBaseParams,
AuthenticateWithCoinbaseWalletParams,
AuthenticateWithGoogleOneTapParams,
AuthenticateWithMetamaskParams,
Expand All @@ -42,6 +43,7 @@ import type {
EnvironmentJSON,
EnvironmentJSONSnapshot,
EnvironmentResource,
GenerateSignatureParams,
GoogleOneTapProps,
HandleEmailLinkVerificationParams,
HandleOAuthCallbackParams,
Expand Down Expand Up @@ -100,6 +102,7 @@ import {
disabledAPIKeysFeature,
disabledOrganizationsFeature,
errorThrower,
generateSignatureWithBase,
generateSignatureWithCoinbaseWallet,
generateSignatureWithMetamask,
generateSignatureWithOKXWallet,
Expand Down Expand Up @@ -2148,6 +2151,13 @@ export class Clerk implements ClerkInterface {
});
};

public authenticateWithBase = async (props: AuthenticateWithBaseParams = {}): Promise<void> => {
await this.authenticateWithWeb3({
...props,
strategy: 'web3_base_signature',
});
};

public authenticateWithOKXWallet = async (props: AuthenticateWithOKXWalletParams = {}): Promise<void> => {
await this.authenticateWithWeb3({
...props,
Expand All @@ -2172,12 +2182,21 @@ export class Clerk implements ClerkInterface {

const provider = strategy.replace('web3_', '').replace('_signature', '') as Web3Provider;
const identifier = await getWeb3Identifier({ provider });
const generateSignature =
provider === 'metamask'
? generateSignatureWithMetamask
: provider === 'coinbase_wallet'
? generateSignatureWithCoinbaseWallet
: generateSignatureWithOKXWallet;
let generateSignature: (params: GenerateSignatureParams) => Promise<string>;
switch (provider) {
case 'metamask':
generateSignature = generateSignatureWithMetamask;
break;
case 'base':
generateSignature = generateSignatureWithBase;
break;
case 'coinbase_wallet':
generateSignature = generateSignatureWithCoinbaseWallet;
break;
default:
generateSignature = generateSignatureWithOKXWallet;
break;
Comment on lines +2196 to +2198
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be falling back to OKXWallet here, but that is the pre-existing functionality

}

const makeNavigate = (to: string) => () =>
customNavigate && typeof customNavigate === 'function' ? customNavigate(to) : this.navigate(to);
Expand Down
16 changes: 12 additions & 4 deletions packages/clerk-js/src/core/resources/SignIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ import type {
} from '@clerk/types';

import {
generateSignatureWithBase,
generateSignatureWithCoinbaseWallet,
generateSignatureWithMetamask,
generateSignatureWithOKXWallet,
getBaseIdentifier,
getCoinbaseWalletIdentifier,
getMetamaskIdentifier,
getOKXWalletIdentifier,
Expand Down Expand Up @@ -143,11 +145,8 @@ export class SignIn extends BaseResource implements SignInResource {
} as PhoneCodeConfig;
break;
case 'web3_metamask_signature':
config = { web3WalletId: factor.web3WalletId } as Web3SignatureConfig;
break;
case 'web3_base_signature':
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a small refactor here to remove the copy-pasta

case 'web3_coinbase_wallet_signature':
config = { web3WalletId: factor.web3WalletId } as Web3SignatureConfig;
break;
case 'web3_okx_wallet_signature':
config = { web3WalletId: factor.web3WalletId } as Web3SignatureConfig;
break;
Expand Down Expand Up @@ -361,6 +360,15 @@ export class SignIn extends BaseResource implements SignInResource {
});
};

public authenticateWithBase = async (): Promise<SignInResource> => {
const identifier = await getBaseIdentifier();
return this.authenticateWithWeb3({
identifier,
generateSignature: generateSignatureWithBase,
strategy: 'web3_base_signature',
});
};

public authenticateWithOKXWallet = async (): Promise<SignInResource> => {
const identifier = await getOKXWalletIdentifier();
return this.authenticateWithWeb3({
Expand Down
17 changes: 17 additions & 0 deletions packages/clerk-js/src/core/resources/SignUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ import type {
} from '@clerk/types';

import {
generateSignatureWithBase,
generateSignatureWithCoinbaseWallet,
generateSignatureWithMetamask,
generateSignatureWithOKXWallet,
getBaseIdentifier,
getCoinbaseWalletIdentifier,
getMetamaskIdentifier,
getOKXWalletIdentifier,
Expand Down Expand Up @@ -276,6 +278,21 @@ export class SignUp extends BaseResource implements SignUpResource {
});
};

public authenticateWithBase = async (
params?: SignUpAuthenticateWithWeb3Params & {
legalAccepted?: boolean;
},
): Promise<SignUpResource> => {
const identifier = await getBaseIdentifier();
return this.authenticateWithWeb3({
identifier,
generateSignature: generateSignatureWithBase,
unsafeMetadata: params?.unsafeMetadata,
strategy: 'web3_base_signature',
legalAccepted: params?.legalAccepted,
});
};

public authenticateWithOKXWallet = async (
params?: SignUpAuthenticateWithWeb3Params & {
legalAccepted?: boolean;
Expand Down
34 changes: 31 additions & 3 deletions packages/clerk-js/src/utils/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export async function getWeb3Identifier(params: GetWeb3IdentifierParams): Promis
}

const identifiers = await ethereum.request({ method: 'eth_requestAccounts' });
// @ts-ignore
// @ts-ignore -- Provider SDKs may return unknown shape; use first address if present
return (identifiers && identifiers[0]) || '';
}

Expand Down Expand Up @@ -58,6 +58,10 @@ export async function getOKXWalletIdentifier(): Promise<string> {
return await getWeb3Identifier({ provider: 'okx_wallet' });
}

export async function getBaseIdentifier(): Promise<string> {
return await getWeb3Identifier({ provider: 'base' });
}

type GenerateSignatureParams = {
identifier: string;
nonce: string;
Expand All @@ -75,6 +79,10 @@ export async function generateSignatureWithOKXWallet(params: GenerateSignaturePa
return await generateWeb3Signature({ ...params, provider: 'okx_wallet' });
}

export async function generateSignatureWithBase(params: GenerateSignatureParams): Promise<string> {
return await generateWeb3Signature({ ...params, provider: 'base' });
}

async function getEthereumProvider(provider: Web3Provider) {
if (provider === 'coinbase_wallet') {
if (__BUILD_DISABLE_RHC__) {
Expand All @@ -90,7 +98,27 @@ async function getEthereumProvider(provider: Web3Provider) {
});
return sdk.getProvider();
}
if (provider === 'base') {
if (__BUILD_DISABLE_RHC__) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot include this in the no-remote-hosted-code builds

clerkUnsupportedEnvironmentWarning('Base');
return null;
}

try {
const createBaseAccountSDK = await import('@base-org/account').then(mod => mod.createBaseAccountSDK);

const sdk = createBaseAccountSDK({
appName:
(typeof window !== 'undefined' &&
(window.Clerk as any)?.__unstable__environment?.displayConfig?.applicationName) ||
(typeof document !== 'undefined' && document.title) ||
'Web3 Application',
});
return sdk.getProvider();
} catch {
return null;
}
}

const injectedWeb3Providers = getInjectedWeb3Providers();
return injectedWeb3Providers.get(provider);
return getInjectedWeb3Providers().get(provider);
}
1 change: 1 addition & 0 deletions packages/clerk-js/vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function viteSvgMockPlugin() {
export default defineConfig({
plugins: [react({ jsxRuntime: 'automatic', jsxImportSource: '@emotion/react' }), viteSvgMockPlugin()],
define: {
__BUILD_DISABLE_RHC__: JSON.stringify(false),
__BUILD_VARIANT_CHIPS__: JSON.stringify(false),
__PKG_NAME__: JSON.stringify('@clerk/clerk-js'),
__PKG_VERSION__: JSON.stringify('test'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export const SignInStartMachine = setup({
if (strategy === 'web3_coinbase_wallet_signature') {
return parent.getSnapshot().context.clerk.client.signIn.authenticateWithCoinbaseWallet();
}
if (strategy === 'web3_base_signature') {
return parent.getSnapshot().context.clerk.client.signIn.authenticateWithBase();
}
if (strategy === 'web3_okx_wallet_signature') {
return parent.getSnapshot().context.clerk.client.signIn.authenticateWithOKXWallet();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export const useThirdPartyProvider = <
return ref.send({ type: 'AUTHENTICATE.ENTERPRISE_SSO' });
}

if (provider === 'base') {
return ref.send({ type: 'AUTHENTICATE.WEB3', strategy: 'web3_base_signature' });
}

if (provider === 'metamask') {
return ref.send({ type: 'AUTHENTICATE.WEB3', strategy: 'web3_metamask_signature' });
}
Expand Down
6 changes: 6 additions & 0 deletions packages/elements/src/react/utils/map-scope-to-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ export function mapScopeToStrategy<T extends `provider:${Strategy}`>(scope: T):
if (scope === 'provider:metamask') {
return 'web3_metamask_signature';
}

if (scope === 'provider:coinbase_wallet') {
return 'web3_coinbase_wallet_signature';
}

if (scope === 'provider:base') {
return 'web3_base_signature';
}

if (scope === 'provider:okx_wallet') {
return 'web3_okx_wallet_signature';
}
Expand Down
10 changes: 10 additions & 0 deletions packages/react/src/isomorphicClerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type {
__internal_UserVerificationProps,
APIKeysNamespace,
APIKeysProps,
AuthenticateWithBaseParams,
AuthenticateWithCoinbaseWalletParams,
AuthenticateWithGoogleOneTapParams,
AuthenticateWithMetamaskParams,
Expand Down Expand Up @@ -1353,6 +1354,15 @@ export class IsomorphicClerk implements IsomorphicLoadedClerk {
}
};

authenticateWithBase = async (params?: AuthenticateWithBaseParams) => {
const callback = () => this.clerkjs?.authenticateWithBase(params);
if (this.clerkjs && this.loaded) {
return callback() as Promise<void>;
} else {
this.premountMethodCalls.set('authenticateWithBase', callback);
}
};

authenticateWithOKXWallet = async (params?: AuthenticateWithOKXWalletParams) => {
const callback = () => this.clerkjs?.authenticateWithOKXWallet(params);
if (this.clerkjs && this.loaded) {
Expand Down
5 changes: 5 additions & 0 deletions packages/shared/src/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export const WEB3_PROVIDERS: Web3ProviderData[] = [
strategy: 'web3_metamask_signature',
name: 'MetaMask',
},
{
provider: 'base',
strategy: 'web3_base_signature',
name: 'Base',
},
{
provider: 'coinbase_wallet',
strategy: 'web3_coinbase_wallet_signature',
Expand Down
13 changes: 13 additions & 0 deletions packages/types/src/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,11 @@
*/
authenticateWithOKXWallet: (params?: AuthenticateWithOKXWalletParams) => Promise<unknown>;

/**
* Authenticates user using Base Account SDK
*/
authenticateWithBase: (params?: AuthenticateWithBaseParams) => Promise<unknown>;

/**
* Authenticates user using their Web3 Wallet browser extension
*/
Expand Down Expand Up @@ -1141,7 +1146,7 @@
*/
windowNavigate: (to: URL | string) => void;
},
) => Promise<unknown> | unknown;

Check warning on line 1149 in packages/types/src/clerk.ts

View workflow job for this annotation

GitHub Actions / Static analysis

'unknown' overrides all other types in this union type

export type WithoutRouting<T> = Omit<T, 'path' | 'routing'>;

Expand Down Expand Up @@ -2179,6 +2184,14 @@
legalAccepted?: boolean;
}

export interface AuthenticateWithBaseParams {
customNavigate?: (to: string) => Promise<unknown>;
redirectUrl?: string;
signUpContinueUrl?: string;
unsafeMetadata?: SignUpUnsafeMetadata;
legalAccepted?: boolean;
}

export interface LoadedClerk extends Clerk {
client: ClientResource;
}
2 changes: 2 additions & 0 deletions packages/types/src/signIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ export interface SignInResource extends ClerkResource {

authenticateWithOKXWallet: () => Promise<SignInResource>;

authenticateWithBase: () => Promise<SignInResource>;

authenticateWithPasskey: (params?: AuthenticateWithPasskeyParams) => Promise<SignInResource>;

createEmailLinkFlow: () => CreateEmailLinkFlowReturn<SignInStartEmailLinkFlowParams, SignInResource>;
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/signUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export interface SignUpResource extends ClerkResource {
authenticateWithMetamask: (params?: SignUpAuthenticateWithWeb3Params) => Promise<SignUpResource>;
authenticateWithCoinbaseWallet: (params?: SignUpAuthenticateWithWeb3Params) => Promise<SignUpResource>;
authenticateWithOKXWallet: (params?: SignUpAuthenticateWithWeb3Params) => Promise<SignUpResource>;
authenticateWithBase: (params?: SignUpAuthenticateWithWeb3Params) => Promise<SignUpResource>;
__internal_toSnapshot: () => SignUpJSONSnapshot;

/**
Expand Down
8 changes: 7 additions & 1 deletion packages/types/src/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export interface Web3ProviderData {
export type MetamaskWeb3Provider = 'metamask';
export type CoinbaseWalletWeb3Provider = 'coinbase_wallet';
export type OKXWalletWeb3Provider = 'okx_wallet';
export type BaseWeb3Provider = 'base';

export type Web3Provider = MetamaskWeb3Provider | CoinbaseWalletWeb3Provider | OKXWalletWeb3Provider;
export type Web3Provider = MetamaskWeb3Provider | BaseWeb3Provider | CoinbaseWalletWeb3Provider | OKXWalletWeb3Provider;

/**
* @deprecated Use `import { WEB3_PROVIDERS } from "@clerk/shared/web3"` instead.
Expand All @@ -23,6 +24,11 @@ export const WEB3_PROVIDERS: Web3ProviderData[] = [
strategy: 'web3_metamask_signature',
name: 'MetaMask',
},
{
provider: 'base',
strategy: 'web3_base_signature',
name: 'Base',
},
{
provider: 'coinbase_wallet',
strategy: 'web3_coinbase_wallet_signature',
Expand Down
Loading
Loading