Skip to content

Commit c34dc0b

Browse files
authored
Merge branch 'main' into ew-dashboard
2 parents 6a3f599 + d185b63 commit c34dc0b

7 files changed

Lines changed: 226 additions & 95 deletions

File tree

embedded-wallets/authentication/id-token.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,11 @@ Every JWKS-based verification call **must** include both `issuer` and `audience`
141141

142142
**Who is at risk without `audience` validation?**
143143

144-
| User identifier used by dapp | Exploitable without `aud`? | Reason |
145-
|---|---|---|
146-
| `userId` / `email` / `authConnectionId` | **Yes** | These claims are set by verifier configuration, which an attacker controls via their own project |
147-
| `wallets[].public_key` (app-scoped key) | No | App keys are derived per-project; a different project produces different keys |
148-
| `wallets[].address` (on-chain address) | No | Bound to the user's cryptographic keys, cannot be forged |
144+
| User identifier used by dapp | Exploitable without `aud`? | Reason |
145+
| --------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------ |
146+
| `userId` / `email` / `authConnectionId` | **Yes** | These claims are set by verifier configuration, which an attacker controls via their own project |
147+
| `wallets[].public_key` (app-scoped key) | No | App keys are derived per-project; a different project produces different keys |
148+
| `wallets[].address` (onchain address) | No | Bound to the user's cryptographic keys, cannot be forged |
149149

150150
If your backend matches users by `userId`, `email`, or `authConnectionId` — the common pattern for Web2-style user management — always validate `audience`.
151151

embedded-wallets/dashboard/project-settings.mdx

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,23 @@ function getKey(header, callback) {
8888
})
8989
}
9090

91-
jwt.verify(token, getKey, options, (err, decoded) => {
92-
if (err) throw new Error('Token verification failed')
93-
return decoded
94-
})
91+
// Verify token
92+
jwt.verify(
93+
token,
94+
getKey,
95+
{
96+
algorithms: ['ES256'],
97+
issuer: 'https://api-auth.web3auth.io',
98+
audience: process.env.WEB3AUTH_CLIENT_ID,
99+
},
100+
(err, decoded) => {
101+
if (err) {
102+
console.error('Token verification failed:', err)
103+
} else {
104+
console.log('Token verified:', decoded)
105+
}
106+
}
107+
)
95108
```
96109

97110
### Project verification key
@@ -105,10 +118,23 @@ const PROJECT_VERIFICATION_KEY = `-----BEGIN PUBLIC KEY-----
105118
<YOUR_PROJECT_VERIFICATION_KEY>
106119
-----END PUBLIC KEY-----`
107120

108-
jwt.verify(token, PROJECT_VERIFICATION_KEY, { algorithms: ['RS256'] }, (err, decoded) => {
109-
if (err) throw new Error('Token verification failed')
110-
return decoded
111-
})
121+
// Verify token with static key
122+
jwt.verify(
123+
token,
124+
PROJECT_VERIFICATION_KEY,
125+
{
126+
algorithms: ['ES256'],
127+
issuer: 'https://api-auth.web3auth.io',
128+
audience: process.env.WEB3AUTH_CLIENT_ID,
129+
},
130+
(err, decoded) => {
131+
if (err) {
132+
console.error('Token verification failed:', err)
133+
} else {
134+
console.log('Token verified:', decoded)
135+
}
136+
}
137+
)
112138
```
113139

114140
:::note

gator_versioned_docs/version-1.2.0/guides/advanced-permissions/use-permissions/erc20-token.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
4646
{
4747
chainId: chain.id,
4848
expiry,
49-
// The requested permissions will granted to the
49+
// The requested permissions will be granted to the
5050
// session account.
5151
to: sessionAccount.address,
5252
permission: {
@@ -70,6 +70,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
7070

7171
```typescript
7272
import { createWalletClient, custom } from 'viem'
73+
import { privateKeyToAccount } from 'viem/accounts'
7374
import { erc7715ProviderActions } from '@metamask/smart-accounts-kit/actions'
7475

7576
export const walletClient = createWalletClient({
@@ -111,7 +112,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
111112
{
112113
chainId: chain.id,
113114
expiry,
114-
// The requested permissions will granted to the
115+
// The requested permissions will be granted to the
115116
// session account.
116117
to: sessionAccount.address,
117118
permission: {

smart-accounts-kit/guides/advanced-permissions/create-redelegation.md

Lines changed: 35 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
7676
import { createWalletClient, custom, createPublicClient, http } from 'viem'
7777
import { privateKeyToAccount } from 'viem/accounts'
7878
import { toMetaMaskSmartAccount, Implementation } from '@metamask/smart-accounts-kit'
79-
import { erc7715ProviderActions } from '@metamask/smart-accounts-kit/actions'
79+
import { erc7715ProviderActions, erc7710WalletActions } from '@metamask/smart-accounts-kit/actions'
8080
import { sepolia as chain } from 'viem/chains'
8181

8282
// USDC address on Ethereum Sepolia.
@@ -90,13 +90,11 @@ const publicClient = createPublicClient({
9090
const privateKey = '0x...'
9191
const account = privateKeyToAccount(privateKey)
9292

93-
export const sessionAccount = await toMetaMaskSmartAccount({
94-
client: publicClient,
95-
implementation: Implementation.Hybrid,
96-
deployParams: [account.address, [], [], []],
97-
deploySalt: '0x',
98-
signer: { account },
99-
})
93+
export const sessionAccount = createWalletClient({
94+
account,
95+
chain,
96+
transport: http(),
97+
}).extend(erc7710WalletActions())
10098

10199
export const walletClient = createWalletClient({
102100
transport: custom(window.ethereum),
@@ -106,30 +104,16 @@ export const walletClient = createWalletClient({
106104
</TabItem>
107105
</Tabs>
108106

109-
## Decode delegations
110-
111-
The granted permissions object includes a `context` property that represents the encoded delegations.
112-
113-
To create a redelegation, you must first decode these delegations to access the
114-
underlying delegations. To decode the delegations, use the [`decodeDelegations`](../../reference/delegation/index.md#decodedelegations) utility function.
115-
116-
```ts
117-
import { decodeDelegations } from '@metamask/smart-accounts-kit/utils'
118-
119-
const permissionContext = grantedPermissions[0].context
120-
121-
const delegations = decodeDelegations(permissionContext)
122-
const rootDelegation = delegations[0]
123-
```
124-
125107
## Create a redelegation
126108

127109
Create a [redelegation](../../concepts/delegation/overview.md#redelegation) from dapp to a Swap agent.
128110

129-
To create a redelegation, provide the signed delegation as the `parentDelegation` argument when calling [`createDelegation`](../../reference/delegation/index.md#createdelegation).
111+
To create a redelegation, provide the granted permission context as the `permissionContext` argument when calling [`redelegatePermissionContext`](../../reference/erc7710/wallet-client.md#redelegatepermissioncontext).
112+
In the previous step, `sessionAccount` was extended with `erc7710WalletActions`.
130113

131-
This example uses the [`erc20TransferAmount`](../delegation/use-delegation-scopes/spending-limit.md#erc-20-transfer-scope) <GlossaryTerm term="Delegation scope">scope</GlossaryTerm>, allowing
132-
dapp to delegate to a Swap agent the ability to spend 5 USDC on user's behalf.
114+
When you create a redelegation, apply the toolkit's [caveats](../../reference/delegation/caveats.md)
115+
to narrow the Swap agent's authority. In this example, we'll use [`erc20TransferAmount`](../../reference/delegation/caveats.md#erc20transferamount)
116+
enforcer, allowing your dapp to delegate the Swap agent only the ability to spend 5 USDC on the user's behalf.
133117

134118
:::note
135119
When creating a redelegation, you can only narrow the scope of the original authority, not expand it.
@@ -139,25 +123,35 @@ When creating a redelegation, you can only narrow the scope of the original auth
139123
<TabItem value="redelegation.ts">
140124

141125
```typescript
142-
import { sessionAccount, agentSmartAccount, tokenAddress } from './config.ts'
143-
import { createDelegation, ScopeType } from '@metamask/smart-accounts-kit'
126+
import { sessionAccount, agentAccount, tokenAddress } from './config.ts'
127+
import {
128+
createDelegation,
129+
ScopeType,
130+
getSmartAccountsEnvironment,
131+
Caveats,
132+
CaveatType,
133+
} from '@metamask/smart-accounts-kit'
144134
import { parseUnits } from 'viem'
135+
import { sepolia as chain } from 'viem/chains'
145136

146-
const redelegation = createDelegation({
147-
scope: {
148-
type: ScopeType.Erc20TransferAmount,
137+
const caveats: Caveats = [
138+
{
139+
type: CaveatType.Erc20TransferAmount,
149140
tokenAddress,
150141
// USDC has 6 decimal places.
151142
maxAmount: parseUnits('5', 6),
152143
},
153-
to: agentSmartAccount.address,
154-
from: sessionAccount.address,
155-
// Signed root delegation extracted from Advanced Permissions.
156-
parentDelegation: rootDelegation,
157-
environment: sessionAccount.environment,
158-
})
144+
]
159145

160-
const signedRedelegation = await sessionAccount.signDelegation({ delegation: redelegation })
146+
const environment = getSmartAccountsEnvironment(chain.id)
147+
148+
const { permissionContext: signedPermissionContext } =
149+
await sessionAccount.redelegatePermissionContext({
150+
to: agentAccount.address,
151+
environment,
152+
permissionContext: grantedPermissions[0].context,
153+
caveats,
154+
})
161155
```
162156

163157
</TabItem>
@@ -166,46 +160,9 @@ const signedRedelegation = await sessionAccount.signDelegation({ delegation: red
166160
```typescript
167161
// Update the existing config to create a smart account for a Swap agent.
168162

169-
const agentAccount = privateKeyToAccount('0x...')
170-
171-
export const agentSmartAccount = await toMetaMaskSmartAccount({
172-
client: publicClient,
173-
implementation: Implementation.Hybrid,
174-
deployParams: [agentAccount.address, [], [], []],
175-
deploySalt: '0x',
176-
signer: { account: agentAccount },
177-
})
163+
const agentPrivateKey = '0x...'
164+
export const agentAccount = privateKeyToAccount(agentPrivateKey)
178165
```
179166

180167
</TabItem>
181168
</Tabs>
182-
183-
### Limit redelegation using caveats
184-
185-
When you create a redelegation, apply the toolkit's [caveats](../../reference/delegation/caveats.md) to narrow the Swap agent's authority. For example, you can limit the authority so Swap agent can use the delegation only once.
186-
187-
To apply caveats, create the `Delegation` object and use [`createCaveatBuilder`](../../reference/delegation/index.md#createcaveatbuilder).
188-
Use [`hashDelegation`](../../reference/delegation/index.md#hashdelegation) to get the delegation hash, then provide it as the `authority` field.
189-
190-
This example uses the [`limitedCalls`](../../reference/delegation/caveats.md#limitedcalls) caveat with a limit of `1`.
191-
192-
```ts
193-
// Use the config from previous step.
194-
import { sessionAccount, agentSmartAccount, tokenAddress } from './config.ts'
195-
import { CaveatType } from '@metamask/smart-accounts-kit'
196-
import { createCaveatBuilder, hashDelegation } from '@metamask/smart-accounts-kit/utils'
197-
198-
const caveatBuilder = createCaveatBuilder(sessionAccount.environment)
199-
200-
const caveats = caveatBuilder.addCaveat(CaveatType.LimitedCalls, { limit: 1 })
201-
202-
const redelegation: Delegation = {
203-
delegate: sessionAccount.address,
204-
delegator: agentSmartAccount.address,
205-
authority: hashDelegation(rootDelegation),
206-
caveats: caveats.build(),
207-
salt: '0x',
208-
}
209-
210-
const signedRedelegation = await sessionAccount.signDelegation({ delegation: redelegation })
211-
```

smart-accounts-kit/guides/advanced-permissions/use-permissions/erc20-token.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
7070

7171
```typescript
7272
import { createWalletClient, custom } from 'viem'
73+
import { privateKeyToAccount } from 'viem/accounts'
7374
import { erc7715ProviderActions } from '@metamask/smart-accounts-kit/actions'
7475

7576
export const walletClient = createWalletClient({
@@ -111,7 +112,7 @@ const grantedPermissions = await walletClient.requestExecutionPermissions([
111112
{
112113
chainId: chain.id,
113114
expiry,
114-
// The requested permissions will granted to the
115+
// The requested permissions will be granted to the
115116
// session account.
116117
to: sessionAccount.address,
117118
permission: {

0 commit comments

Comments
 (0)