docs: web3 and some other js reference improvements (#38670)

* docs: web3 and some other js reference improvements

* add MetaMask to spell rules

* apply suggestion from @cemalkilic

Co-authored-by: Cemal Kılıç <cemalkilic@users.noreply.github.com>

* fix tests

* test: update snapshot

---------

Co-authored-by: Cemal Kılıç <cemalkilic@users.noreply.github.com>
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2025-09-15 14:56:34 +02:00
1 parent 33f59a5a4a
commit e8c158bc48
11 files changed
+4241 -3990

No files matched your search

@@ -699,7 +699,7 @@ export const auth: NavMenuConstant = {
enabled: allAuthProvidersEnabled,
},
{
name: 'Web3 (Sign in with Solana)',
name: 'Web3 (Ethereum or Solana)',
url: '/guides/auth/auth-web3',
enabled: allAuthProvidersEnabled,
},
+92 -5
View File
@@ -9,17 +9,43 @@ subtitle: 'Use your Web3 wallet to authenticate users with Supabase'
Supported Web3 wallets:
- All Solana wallets
- Coming soon: All Ethereum wallets
- All Ethereum wallets
## How does it work?
Sign in with Web3 utilizes the [EIP 4361](https://eips.ethereum.org/EIPS/eip-4361) standard to authenticate wallet addresses off-chain. This standard is adopted by the Solana ecosystem with some minor differences from Ethereum.
Sign in with Web3 utilizes the [EIP 4361](https://eips.ethereum.org/EIPS/eip-4361) standard to authenticate wallet addresses off-chain. This standard is widely supported by the Ethereum and Solana ecosystems, making it the best choice for verifying wallet ownership.
Authentication works by asking the Web3 wallet application to sign a predefined message with the user's wallet. This message is parsed both by the Web3 wallet application and Supabase Auth to verify its validity and purpose, before creating a user account or session.
The Web3 wallet application uses the information contained in the message to provide the user with a confirmation dialog, asking whether they want to allow sign in with your project.
An example of such a message is:
Not all Web3 wallet applications show a dedicated confirmation dialog for these sign in messages. In that case the Web3 wallet shows a traditional message signature confirmation dialog.
```
example.com wants you to sign in with your Ethereum account:
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
I accept the ExampleOrg Terms of Service: https://example.com/tos
URI: https://example.com/login
Version: 1
Chain ID: 1
Nonce: 32891756
Issued At: 2021-09-30T16:25:24Z
Resources:
- https://example.com/my-web2-claim.json
```
It defines the wallet address, timestamp, browser location where the sign-in occurred and includes a customizable statement (`I accept...`) which you can use to ask consent from the user.
Most Web3 wallets are able to recognize these messages and show a dedicated "Confirm Sign In" dialog validating and presenting the information in the message in a secure and responsible way to the user. Even if the wallet does not directly support these messages, it will use the message signature dialog instead.
Finally the Supabase Auth server validates both the message's contents and signature before issuing a valid [User session](/docs/guides/auth/sessions) to your application. Validation rules include:
- Message structure validation
- Cryptographic signature verification
- Timestamp validation, ensuring the signature was created within 10 minutes of the sign-in call
- URI and Domain validation, ensuring these match your server's defined [Redirect URLs](/docs/guides/auth/redirect-urls)
The wallet address is used as the identity identifier, and in the identity data you can also find the statement and additional metadata.
## Enable the Web3 provider
@@ -30,6 +56,9 @@ In the CLI add the following config to your `supabase/config.toml` file:
```toml
[auth.web3.solana]
enabled = true
[auth.web3.ethereum]
enabled = true
```
### Potential for abuse
@@ -63,7 +92,65 @@ For example if the user is signing in to the page `https://example.com/sign-in`
## Sign in with Ethereum
Sign in with Ethereum wallets is coming soon.
Ethereum defines the [`window.ethereum` global scope object](https://eips.ethereum.org/EIPS/eip-1193) that your app uses to interact with Ethereum Wallets. Additionally there is a [wallet discovery mechanism (EIP-6963)](https://eips.ethereum.org/EIPS/eip-6963) that your app can use to discover all of the available wallets on the user's browser.
To sign in a user with their Ethereum wallet make sure that the user has installed a wallet application. There are two ways to do this:
1. Detect the `window.ethereum` global scope object and ensure it's defined. This only works if your user has only one wallet installed on their browser.
2. Use the wallet discovery mechanism (EIP-6963) to ask the user to choose a wallet before they continue to sign in. Read [the MetaMask guide on the best way to support this](https://docs.metamask.io/wallet/tutorials/react-dapp-local-state).
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="window"
queryGroup="ethWallet"
>
<TabPanel id="window" label="Ethereum Window API (EIP-1193)">
Use the following code to sign in a user, implicitly relying on the `window.ethereum` global scope wallet API:
```typescript
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'ethereum',
statement: 'I accept the Terms of Service at https://example.com/tos',
})
```
</TabPanel>
<TabPanel id="wallet" label="Ethereum Wallet API (EIP-6963)">
Once you've obtained a wallet using the wallet detection (EIP-6963) mechanism, you can pass the selected wallet to the Supabase JavaScript SDK to continue the sign-in process.
```typescript
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'ethereum',
statement: 'I accept the Terms of Service at https://example.com/tos',
wallet: selectedWallet, // obtain this using the EIP-6963 mechanism
})
```
An excellent guide on using the [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) mechanism is available by [MetaMask](https://docs.metamask.io/wallet/tutorials/react-dapp-local-state).
</TabPanel>
<TabPanel id="custom" label="Ethereum Message and Signature">
If your application relies on a custom Ethereum wallet API, you can pass a [Sign in with Ethereum (EIP-4361)](https://eips.ethereum.org/EIPS/eip-4361) message and signature to complete the sign in process.
```typescript
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'ethereum',
message: '<sign in with ethereum message>',
signature: '<hex of the ethereum signature over the message>',
})
```
</TabPanel>
</Tabs>
## Sign in with Solana
@@ -16313,7 +16313,7 @@ exports[`TS type spec parsing > matches snapshot 1`] = `
},
"isOptional": true,
"comment": {
"shortText": "Optional statement to include in the Sign in with Solana message. Must not include new line characters. Most wallets like Phantom **require specifying a statement!**"
"shortText": "Optional statement to include in the Sign in with Ethereum message. Must not include new line characters. Most wallets like Phantom **require specifying a statement!**"
}
},
{
@@ -16324,7 +16324,7 @@ exports[`TS type spec parsing > matches snapshot 1`] = `
},
"isOptional": true,
"comment": {
"shortText": "Wallet interface to use. If not specified will default to \`window.solana\`."
"shortText": "Wallet interface to use. If not specified will default to \`window.ethereum\`."
}
}
]
@@ -16376,7 +16376,7 @@ exports[`TS type spec parsing > matches snapshot 1`] = `
"name": "Hex"
},
"comment": {
"shortText": "Ed25519 signature of the message."
"shortText": "Ethereum curve (secp256k1) signature of the message."
}
}
]
+12 -4
View File
@@ -4846,7 +4846,8 @@
"type": "object",
"properties": { "id": { "type": "number" }, "username": { "type": "string" } },
"required": ["id", "username"]
}
},
"favorite": { "type": "boolean" }
},
"required": [
"id",
@@ -4858,7 +4859,8 @@
"description",
"project",
"owner",
"updated_by"
"updated_by",
"favorite"
]
}
},
@@ -4891,14 +4893,19 @@
"properties": { "id": { "type": "number" }, "username": { "type": "string" } },
"required": ["id", "username"]
},
"favorite": { "type": "boolean" },
"content": {
"type": "object",
"properties": {
"favorite": { "type": "boolean" },
"favorite": {
"type": "boolean",
"deprecated": true,
"description": "Deprecated: Rely on root-level favorite property instead."
},
"schema_version": { "type": "string" },
"sql": { "type": "string" }
},
"required": ["favorite", "schema_version", "sql"]
"required": ["schema_version", "sql"]
}
},
"required": [
@@ -4912,6 +4919,7 @@
"project",
"owner",
"updated_by",
"favorite",
"content"
]
},
@@ -450,7 +450,7 @@
},
{
"id": "sign-in-with-id-token",
"title": "Sign in with ID Token",
"title": "Sign in with ID token (native sign-in)",
"slug": "auth-signinwithidtoken",
"product": "auth",
"type": "function"
@@ -490,6 +490,13 @@
"product": "auth",
"type": "function"
},
{
"id": "sign-in-with-web3",
"title": "Sign in a user through Web3 (Solana, Ethereum)",
"slug": "auth-signinwithweb3",
"product": "auth",
"type": "function"
},
{
"id": "get-claims",
"title": "Get user claims from verified JWT",
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+142 -14
View File
@@ -793,7 +793,7 @@ functions:
- The magic link's destination URL is determined by the [`SITE_URL`](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls).
- See [redirect URLs and wildcards](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls) to add additional redirect URLs to your project.
- Magic links and OTPs share the same implementation. To send users a one-time code instead of a magic link, [modify the magic link email template](/dashboard/project/_/auth/templates) to include `{{ .Token }}` instead of `{{ .ConfirmationURL }}`.
- See our [Twilio Phone Auth Guide](/docs/guides/auth/phone-login?showSmsProvider=Twilio) for details about configuring WhatsApp sign in.
- See our [Twilio Phone Auth Guide](/docs/guides/auth/phone-login?showSMSProvider=Twilio) for details about configuring WhatsApp sign in.
examples:
- id: sign-in-with-email
name: Sign in with email
@@ -845,8 +845,8 @@ functions:
title: 'signInWithOAuth()'
$ref: '@supabase/auth-js.GoTrueClient.signInWithOAuth'
notes: |
- This method is used for signing in using a third-party provider.
- Supabase supports many different [third-party providers](/docs/guides/auth#configure-third-party-providers).
- This method is used for signing in using [Social Login (OAuth) providers](/docs/guides/auth#configure-third-party-providers).
- It works by redirecting your application to the provider's authorization screen, before bringing back the user to your app.
examples:
- id: sign-in-using-a-third-party-provider
name: Sign in using a third-party provider
@@ -871,7 +871,7 @@ functions:
name: Sign in using a third-party provider with redirect
isSpotlight: false
description: |
- When the third-party provider successfully authenticates the user, the provider redirects the user to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls). It does not redirect the user immediately after invoking this method.
- When the OAuth provider successfully authenticates the user, they are redirected to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls). It does not redirect the user immediately after invoking this method.
- See [redirect URLs and wildcards](/docs/guides/auth/redirect-urls#use-wildcards-in-redirect-urls) to add additional redirect URLs to your project.
code: |
```js
@@ -924,6 +924,10 @@ functions:
- id: sign-in-with-id-token
title: 'signInWithIdToken'
$ref: '@supabase/auth-js.GoTrueClient.signInWithIdToken'
notes: |
- Use an ID token to sign in.
- Especially useful when implementing sign in using native platform dialogs in mobile or desktop apps using Sign in with Apple or Sign in with Google on iOS and Android.
- You can also use Google's [One Tap](https://developers.google.com/identity/gsi/web/guides/display-google-one-tap) and [Automatic sign-in](https://developers.google.com/identity/gsi/web/guides/automatic-sign-in-sign-out) via this API.
examples:
- id: sign-in-with-id-token
name: 'Sign In using ID Token'
@@ -1033,12 +1037,109 @@ functions:
window.location.href = data.url
}
```
- id: sign-in-with-web3
title: 'signInWithWeb3()'
$ref: '@supabase/auth-js.GoTrueClient.signInWithWeb3'
notes: |
- Uses a Web3 (Ethereum, Solana) wallet to sign a user in.
- Read up on the [potential for abuse](/docs/guides/auth/auth-web3#potential-for-abuse) before using it.
examples:
- id: sign-in-with-solana-window
name: Sign in with Solana or Ethereum (Window API)
isSpotlight: true
code: |
```js
// uses window.ethereum for the wallet
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'ethereum',
statement: 'I accept the Terms of Service at https://example.com/tos'
})
// uses window.solana for the wallet
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'solana',
statement: 'I accept the Terms of Service at https://example.com/tos'
})
```
- id: sign-in-with-ethereum-raw
name: Sign in with Ethereum (Message and Signature)
isSpotlight: true
code: |
```js
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'ethereum',
message: '<sign in with ethereum message>',
signature: '<hex of the ethereum signature over the message>',
})
```
- id: sign-in-with-solana-brave
name: Sign in with Solana (Brave)
isSpotlight: false
code: |
```js
const { data, error } = await supabase.auth.signInWithWeb3({
chain: 'solana',
statement: 'I accept the Terms of Service at https://example.com/tos',
wallet: window.braveSolana
})
```
- id: sign-in-with-solana-wallet-adapter
name: Sign in with Solana (Wallet Adapter)
isSpotlight: false
code: |
```jsx
function SignInButton() {
const wallet = useWallet()
return (
<>
{wallet.connected ? (
<button
onClick={() => {
supabase.auth.signInWithWeb3({
chain: 'solana',
statement: 'I accept the Terms of Service at https://example.com/tos',
wallet,
})
}}
>
Sign in with Solana
</button>
) : (
<WalletMultiButton />
)}
</>
)
}
function App() {
const endpoint = clusterApiUrl('devnet')
const wallets = useMemo(() => [], [])
return (
<ConnectionProvider endpoint={endpoint}>
<WalletProvider wallets={wallets}>
<WalletModalProvider>
<SignInButton />
</WalletModalProvider>
</WalletProvider>
</ConnectionProvider>
)
}
```
- id: get-claims
title: 'getClaims()'
$ref: '@supabase/auth-js.GoTrueClient.getClaims'
notes: |
- Parses the user's [access token](/docs/guides/auth/sessions#access-token-jwt-claims) as a [JSON Web Token (JWT)](/docs/guides/auth/jwts) and returns its components if valid and not expired.
- If your project is using asymmetric JWT signing keys, then the verification is done locally usually without a network request using the [WebCrypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API).
- A network request is sent to your project's JWT signing key discovery endpoint `https://project-id.supabase.co/auth/v1/.well-known/jwks.json`, which is cached locally. If your environment is ephemeral, such as a Lambda function that is destroyed after every request, a network request will be sent for each new invocation. Supabase provides a network-edge cache providing fast responses for these situations.
- If the user's access token is about to expire when calling this function, the user's session will first be refreshed before validating the JWT.
- If your project is using a symmetric secret to sign the JWT, it always sends a request similar to `getUser()` to validate the JWT at the server before returning the decoded token. This is also used if the WebCrypto API is not available in the environment. Make sure you polyfill it in such situations.
- The returned claims can be customized per project using the [Custom Access Token Hook](/docs/guides/auth/auth-hooks/custom-access-token-hook).
examples:
- id: get-claims
name: Get user object
name: Get JWT claims, header and signature
code: |
```js
const { data, error } = await supabase.auth.getClaims()
@@ -1059,7 +1160,7 @@ functions:
"exp": 1715769600,
"iat": 1715766000,
"is_anonymous": false,
"iss": "https://api.supabase.com/auth/v1",
"iss": "https://project-id.supabase.co/auth/v1",
"phone": "+13334445555",
"role": "authenticated",
"session_id": "11111111-1111-1111-1111-111111111111",
@@ -1069,7 +1170,7 @@ functions:
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "abcdefgh"
"kid": "11111111-1111-1111-1111-111111111111"
},
"signature": [/** Uint8Array */],
},
@@ -1081,16 +1182,30 @@ functions:
$ref: '@supabase/auth-js.GoTrueClient.signOut'
notes: |
- In order to use the `signOut()` method, the user needs to be signed in first.
- By default, `signOut()` uses the global scope, which signs out all other sessions that the user is logged into as well.
- By default, `signOut()` uses the global scope, which signs out all other sessions that the user is logged into as well. Customize this behavior by passing a scope parameter.
- Since Supabase Auth uses JWTs for authentication, the access token JWT will be valid until it's expired. When the user signs out, Supabase revokes the refresh token and deletes the JWT from the client-side. This does not revoke the JWT and it will still be valid until it expires.
examples:
- id: sign-out
name: Sign out
name: Sign out (all sessions)
isSpotlight: true
code: |
```js
const { error } = await supabase.auth.signOut()
```
- id: sign-out-current-session
name: Sign out (current session)
isSpotlight: false
code: |
```js
const { error } = await supabase.auth.signOut('local')
```
- id: sign-out-other-sessions
name: Sign out (other sessions)
isSpotlight: false
code: |
```js
const { error } = await supabase.auth.signOut('others')
```
- id: verify-otp
title: 'verifyOtp()'
$ref: '@supabase/auth-js.GoTrueClient.verifyOtp'
@@ -1218,7 +1333,7 @@ functions:
}
```
- id: verify-sms-one-time-password(otp)
name: Verify Sms One-Time Password (OTP)
name: Verify SMS One-Time Password (OTP)
isSpotlight: true
code: |
```js
@@ -1235,10 +1350,13 @@ functions:
title: 'getSession()'
$ref: '@supabase/auth-js.GoTrueClient.getSession'
notes: |
- This method retrieves the current local session (i.e local storage).
- The session contains a signed JWT and unencoded session data.
- Since the unencoded session data is retrieved from the local storage medium, **do not** rely on it as a source of trusted data on the server. It could be tampered with by the sender. If you need verified, trustworthy user data, call [`getUser`](/docs/reference/javascript/auth-getuser) instead.
- If the session has an expired access token, this method will use the refresh token to get a new session.
- Since the introduction of [asymmetric JWT signing keys](/docs/guides/auth/signing-keys), this method is considered low-level and we encourage you to use `getClaims()` or `getUser()` instead.
- Retrieves the current [user session](/docs/guides/auth/sessions) from the storage medium (local storage, cookies).
- The session contains an access token (signed JWT), a refresh token and the user object.
- If the session's access token is expired or is about to expire, this method will use the refresh token to refresh the session.
- When using in a browser, or you've called `startAutoRefresh()` in your environment (React Native, etc.) this function always returns a valid access token without refreshing the session itself, as this is done in the background. This function returns very fast.
- **IMPORTANT SECURITY NOTICE:** If using an insecure storage medium, such as cookies or request headers, the user object returned by this function **must not be trusted**. Always verify the JWT using `getClaims()` or your own JWT verification library to securely establish the user's identity and access. You can also use `getUser()` to fetch the user object directly from the Auth server for this purpose.
- When using in a browser, this function is synchronized accross all tabs using the [LockManager](https://developer.mozilla.org/en-US/docs/Web/API/LockManager) API. In other environments make sure you've defined a proper `lock` property, if necessary, to make sure there are no race conditions while the session is being refreshed.
examples:
- id: get-the-session-data
name: Get the session data
@@ -3077,6 +3195,16 @@ functions:
{ phone_confirm: true }
)
```
- id: ban-a-user
name: Ban a user for 100 years
isSpotlight: false
code: |
```js
const { data: user, error } = await supabase.auth.admin.updateUserById(
'6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4',
{ ban_duration: '100y' }
)
```
- id: mfa-list-factors-admin
title: 'mfa.listFactors()'
$ref: '@supabase/auth-js.GoTrueAdminMFAApi.listFactors'
@@ -1494,6 +1494,9 @@
}
},
"required": ["id", "username"]
},
"favorite": {
"type": "boolean"
}
},
"required": [
@@ -1506,7 +1509,8 @@
"description",
"project",
"owner",
"updated_by"
"updated_by",
"favorite"
]
}
},
@@ -1614,11 +1618,16 @@
},
"required": ["id", "username"]
},
"favorite": {
"type": "boolean"
},
"content": {
"type": "object",
"properties": {
"favorite": {
"type": "boolean"
"type": "boolean",
"deprecated": true,
"description": "Deprecated: Rely on root-level favorite property instead."
},
"schema_version": {
"type": "string"
@@ -1627,7 +1636,7 @@
"type": "string"
}
},
"required": ["favorite", "schema_version", "sql"]
"required": ["schema_version", "sql"]
}
},
"required": [
@@ -1641,6 +1650,7 @@
"project",
"owner",
"updated_by",
"favorite",
"content"
]
}
@@ -16006,6 +16016,9 @@
}
},
"required": ["id", "username"]
},
"favorite": {
"type": "boolean"
}
},
"required": [
@@ -16018,7 +16031,8 @@
"description",
"project",
"owner",
"updated_by"
"updated_by",
"favorite"
]
}
},
@@ -16091,11 +16105,16 @@
},
"required": ["id", "username"]
},
"favorite": {
"type": "boolean"
},
"content": {
"type": "object",
"properties": {
"favorite": {
"type": "boolean"
"type": "boolean",
"deprecated": true,
"description": "Deprecated: Rely on root-level favorite property instead."
},
"schema_version": {
"type": "string"
@@ -16104,7 +16123,7 @@
"type": "string"
}
},
"required": ["favorite", "schema_version", "sql"]
"required": ["schema_version", "sql"]
}
},
"required": [
@@ -16118,6 +16137,7 @@
"project",
"owner",
"updated_by",
"favorite",
"content"
]
},
+1
View File
@@ -69,6 +69,7 @@ allow_list = [
"[Ll]iveness",
"[Mm]atryoshka",
"[Mm]essageBird",
"MetaMask",
"[Mm]icroservices?",
"[Mm]iddlewares?",
"[Mm]onorepos?",