-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Running into an issue with passkeys and viem. #177
Comments
Hi @Watcher-eth, thanks for reaching out. First of all, sorry to hear this! Otherwise, a quick sanity check -- are you able to run any examples, like this one? Alternatively, are you able to successfully query our whoami endpoint? Just want to verify that the credentials are valid. Also, what activity are you attempting when you run into |
Hey so I haven't tried any other examples yet because I am building a pwa so I figured that would be the perfect example. Are there any good ones you can point me to? I basically have the following specifications: Im building a consumer social app and we want to support onboarding both for existing wallets (we have implemented connect kit) and also new users through passkeys (side question is it possible to allow existing wallets to use passkeys for signing as well?). For new users I want to be able to issue them a new wallet with passkeys and then store their keys to build a seamless UX. I will also attach some of my current code so you can maybe understand my error better: //api/turnkey/create-user import type { NextApiRequest, NextApiResponse } from 'next' dotenv.config({ path: '../../../.env.local' }) // Replace with the actual path to your .env file type TResponse = { export default async function createKey( try {
} catch (e) {
} //Client const handleCreateSubOrgClick = async () => { |
@Watcher-eth can you try running this one locally https://github.com/tkhq/demo-viem-passkeys ? Just to sanity check that your authenticator/orgs are correctly configured. Assuming that's the case, my hunch would be that there might be a mismatch when you attempt to authenticate a request using a passkey/credential for a specific user/org. I haven't had the chance to dig in too deeply here with this integrated example, but will try to investigate further in a bit
By existing wallets, are you referring to users' self-custody wallets (such as Metamask/Coinbase Wallet/etc)? If so, unfortunately not.
This sounds great! 🙌 |
Thank you very much my keys were wrong and I had to update my api but I got it working now. However that brings me to the next question. I have my wallet, my subOrgId and my private key all stored correctly in my DB now. However when I try to sign a message I get the following error. Using this function: const viemClient = createWalletClient({ const signedMessage = await viemClient.signMessage({ return { Im getting this error every time: Also when I am prompted to sign with Passkeys I get to choose and I have a lot of them with the same name and im not sure if it matters which one I use? I tried multiple but non of them worked. |
Thank you again for your quick help! Maybe you can pinpoint me in the right direction again. Basically all I need once my users have created their wallet is a way to sign a Message and to signTypedData. (using the viem client) Ive set up two utility functions according to the viem documentation but they don't seem to be working. // @ts-nocheck import { TurnkeyClient } from '@turnkey/http' const passkeyHttpClient = new TurnkeyClient( export const signMessage = async ( const viemClient = createWalletClient({ const signedMessage = await viemClient.signMessage({ return { export const signTypedData = async ( const viemClient = createWalletClient({ const signedMessage = await viemClient.signTypedData({ return { |
Hey there, sorry for the delayed response. For the most part, that looks reasonable to me — can you share the error message you've been encountering? For reference, here's an example of how our Turnkey Viem client is created + invoked: sdk/examples/with-viem/src/advanced.ts Line 59 in 4113761
|
Ive been unsuccesfully trying to integrate your anagram pwa passkey example for a couple weeks now but im stuck. I set everything up to instructions however already had issues when trying to generate the public/private keypair through the cli. I managed to create a public a api key and a private key through the dashboard but cant get passkeys working. Ill attach my code butI have pretty muchs trcitly stuck to the anagram demo. Im either getting a parsing error - Turnkey error 3 or a Turnkey error 16: no valid user found for authenticator: rpc error: code = Unauthenticated desc = no valid authentication signature found for request:.
I have also tried using the new ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V3 but that didnt work either. Help would be very appreicated.
//create user api route
import type { NextApiRequest, NextApiResponse } from 'next'
import { getAuth } from '@clerk/nextjs/server'
import { TurnkeyApiTypes, TurnkeyClient } from '@turnkey/http'
import { createActivityPoller } from '@turnkey/http/dist/async'
import { ApiKeyStamper } from '@turnkey/api-key-stamper'
import { users } from '@shared/db/schema'
import { db } from '@shared/db/drizzle'
import { eq } from 'drizzle-orm'
import { first } from 'lodash'
import { refineNonNull } from '@shared/client-utils'
import * as dotenv from 'dotenv'
dotenv.config({ path: '../../../.env.local' }) // Replace with the actual path to your .env file
type TAttestation = TurnkeyApiTypes['v1Attestation']
type CreateSubOrgRequest = {
subOrgName: string
challenge: string
attestation: TAttestation
}
type CreateSubOrgResponse = {
subOrgId: string
addresses: Array<{ format?: any; address?: string }>
createdAddress: { format?: any; address?: string }
privateKeyId: string
}
type ErrorMessage = {
message: string
}
/**
For a new user:
Creates a sub org on TurnKey for the user and it's first key pair
After this function runs successfully, we'll have a new secure non-custodial wallet for the user ready to use.
@param req
@param res
@returns
*/
export default async function createUser(
req: NextApiRequest,
res: NextApiResponse<CreateSubOrgResponse | ErrorMessage>,
) {
try {
const { userId } = getAuth(req)
if (!userId) {
return res.status(401).json({ message: 'Unauthorized' })
}
const createSubOrgRequest = req.body as CreateSubOrgRequest
// Log out API environment variables for debugging
console.log(
'NEXT_PUBLIC_TURNKEY_API_BASE_URL:',
process.env.NEXT_PUBLIC_TURNKEY_API_BASE_URL,
req.body,
)
console.log(
'NEXT_PUBLIC_TURNKEY_API_PUBLIC_KEY:',
process.env.NEXT_PUBLIC_TURNKEY_API_PUBLIC_KEY,
)
console.log(
'NEXT_PUBLIC_TURNKEY_API_PRIVATE_KEY:',
process.env.NEXT_PUBLIC_TURNKEY_API_PRIVATE_KEY,
)
console.log(
'NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID:',
process.env.NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID,
)
console.log(
'NEXT_PUBLIC_TURNKEY_BACKEND_API_KEY_NAME:',
process.env.NEXT_PUBLIC_TURNKEY_BACKEND_API_KEY_NAME,
)
const turnkeyClient = new TurnkeyClient(
{ baseUrl: process.env.NEXT_PUBLIC_TURNKEY_API_BASE_URL! },
new ApiKeyStamper({
apiPublicKey: process.env.NEXT_PUBLIC_TURNKEY_API_PUBLIC_KEY!,
apiPrivateKey: process.env.NEXT_PUBLIC_TURNKEY_API_PRIVATE_KEY!,
}),
)
const activityPoller = createActivityPoller({
client: turnkeyClient,
requestFn: turnkeyClient.createSubOrganization,
})
// Create sub org on turnkey for user...
const completedActivity = await activityPoller({
type: 'ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V2',
timestampMs: String(Date.now()),
organizationId: process.env.NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID!,
parameters: {
subOrganizationName: createSubOrgRequest.subOrgName,
},
})
console.log(
'Turnkey Request Payload:',
JSON.stringify(completedActivity, null, 2),
)
const subOrgId = refineNonNull(
completedActivity.result.createSubOrganizationResult?.subOrganizationId,
)
if (!subOrgId) {
// Handle the error or log a message
console.error('Invalid subOrgId:', subOrgId)
return res.status(500).json({ message: 'Invalid subOrgId' })
}
const activityPollerForCreatePrivateKeys = createActivityPoller({
client: turnkeyClient,
requestFn: turnkeyClient.createPrivateKeys,
})
// Ask turnkey to create a new public/private key for the user...
const createKeyPairForSubOrg = await activityPollerForCreatePrivateKeys({
type: 'ACTIVITY_TYPE_CREATE_PRIVATE_KEYS_V2',
organizationId: subOrgId,
timestampMs: String(Date.now()),
parameters: {
privateKeys: [
{
privateKeyName:
ETH Key ${Math.floor(Math.random() * 1000)}
,curve: 'CURVE_SECP256K1',
addressFormats: ['ADDRESS_FORMAT_ETHEREUM'],
privateKeyTags: [],
},
],
},
})
console.log(
'Turnkey Response:',
JSON.stringify(createKeyPairForSubOrg, null, 2),
)
const createSubOrgKeyPairResult = first(
createKeyPairForSubOrg.result.createPrivateKeysResultV2?.privateKeys,
)
const addresses = refineNonNull(createSubOrgKeyPairResult?.addresses)
// On initial suborg bootstrap, this is always the first key
const createdAddress = refineNonNull(first(addresses))
// Get the private key id (not the private key itself) to save to the database.
// We use this private key id on the TurnKey API to request and sign transactions
const privateKeyId = refineNonNull(createSubOrgKeyPairResult?.privateKeyId)
await db
.update(users)
.set({
turnkey_suborg: subOrgId,
turnkey_private_key_id: privateKeyId,
turnkey_private_key_public_address: createdAddress?.address,
})
.where(eq(users.external_auth_provider_user_id, userId))
res.status(200).json({
subOrgId,
createdAddress,
addresses: addresses,
privateKeyId: privateKeyId,
})
} catch (e) {
console.error('Error in createUser:', e)
res.status(500).json({
message: 'Something went wrong.',
error: e.message, // Add more details if needed
})
}
}
// ENV (Will update the actual codes for production this is just to make it easier to find my error)
NEXT_PUBLIC_TURNKEY_API_PUBLIC_KEY: 02811e22530d37b02a98409fa97e5b66d76c121655d28d0db39dd395060b67e83e
NEXT_PUBLIC_TURNKEY_API_PRIVATE_KEY: 159363b1f56c4c50a93c51630cc8ea8f
NEXT_PUBLIC_TURNKEY_ORGANIZATION_ID: ea4f6d5e-9911-4f35-b442-bd81451200e7
NEXT_PUBLIC_TURNKEY_BACKEND_API_KEY_NAME: api-demo
The text was updated successfully, but these errors were encountered: