Documentation Index
Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
Use this file to discover all available pages before exploring further.
Verify an embedded wallet user on your backend by accepting an ID token from the client and checking its signature and claims against the staging issuer.
This guide is for the staging issuer at https://d26giflyqapd29.cloudfront.net. Use the production issuer and JWKS URL when verifying production tokens.
1. Send the ID token to your backend
After the user authenticates in the app, request an ID token for the active wallet. Send only the returned idToken string to your backend over HTTPS.
await oms.wallet.startEmailAuth({ email: 'user@example.com' })
await oms.wallet.completeEmailAuth({ code: '123456' })
const idToken = await oms.wallet.getIdToken({
ttlSeconds: 300,
})
await fetch('/api/wallet-session', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ idToken }),
})
try await oms.wallet.startEmailAuth(email: "user@example.com")
try await oms.wallet.completeEmailAuth(code: "123456")
let idToken = try await oms.wallet.getIdToken(ttlSeconds: 300)
var request = URLRequest(url: URL(string: "https://api.example.com/wallet-session")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "content-type")
request.httpBody = try JSONEncoder().encode(["idToken": idToken])
_ = try await URLSession.shared.data(for: request)
import com.omsclient.kotlin_sdk.wallet.CompleteAuthResult
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
val okHttpClient = OkHttpClient()
client.wallet.startEmailAuth("user@example.com")
val auth = client.wallet.completeEmailAuth("123456")
check(auth is CompleteAuthResult.WalletSelected)
val idToken = client.wallet.getIdToken(ttlSeconds = 300u)
val body = Json.encodeToString(
buildJsonObject {
put("idToken", idToken)
},
)
val request = Request.Builder()
.url("https://api.example.com/wallet-session")
.post(body.toRequestBody("application/json".toMediaType()))
.build()
okHttpClient.newCall(request).execute().use { response ->
check(response.isSuccessful)
}
2. Verify the token signature and claims
Fetch keys from the staging JWKS endpoint and use a JWT library to verify the token. The library should select the signing key from the JWT header kid.
For staging, validate:
| Claim | Expected value |
|---|
iss | https://d26giflyqapd29.cloudfront.net |
aud | Contains your OMS project ID |
exp | Is not in the past |
import { createRemoteJWKSet, jwtVerify } from 'jose'
const STAGING_ISSUER = 'https://d26giflyqapd29.cloudfront.net'
const STAGING_JWKS = new URL(`${STAGING_ISSUER}/.well-known/jwks.json`)
const jwks = createRemoteJWKSet(STAGING_JWKS)
type VerifiedWalletUser = {
walletAddress: string
walletType: 'ethereum'
walletId: string
email?: string
}
export async function verifyWalletIdToken(
idToken: string,
projectId: string,
): Promise<VerifiedWalletUser> {
const { payload } = await jwtVerify(idToken, jwks, {
issuer: STAGING_ISSUER,
audience: projectId,
})
if (payload.wallet_type !== 'ethereum') {
throw new Error('Unexpected wallet_type claim')
}
if (typeof payload.wallet_address !== 'string' || payload.wallet_address.length === 0) {
throw new Error('Missing wallet_address claim')
}
if (typeof payload.sub !== 'string' || payload.sub.length === 0) {
throw new Error('Missing sub claim')
}
return {
walletAddress: payload.wallet_address,
walletType: payload.wallet_type,
walletId: payload.sub,
email: typeof payload.email === 'string' ? payload.email : undefined,
}
}
3. Use the wallet claims
After verification succeeds, trust the claims from the verified JWT payload for the current request.
| Claim | Description |
|---|
wallet_address | User’s wallet address. |
wallet_type | Wallet type. This is always ethereum. |
sub | Internal wallet ID. |
email | User’s email address, when available. |
app.post('/api/wallet-session', async (req, res) => {
const idToken = req.body.idToken
const projectId = process.env.OMS_PROJECT_ID
if (typeof idToken !== 'string' || !projectId) {
res.status(400).json({ error: 'Missing token or project ID' })
return
}
try {
const user = await verifyWalletIdToken(idToken, projectId)
res.json({
walletAddress: user.walletAddress,
walletId: user.walletId,
email: user.email ?? null,
})
} catch {
res.status(401).json({ error: 'Invalid wallet token' })
}
})