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
4 changes: 3 additions & 1 deletion grid_api/routers/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ transport, accounts, stats, health/metrics.
wallet, then verified email only when it is the sole identity); supplemental
or unverified email must never join accounts.
Native service/app exchange lives at `/v1/auth/service/exchange`; Google ID
tokens are verified at `/v1/auth/google/exchange`; partner wallet proof uses
tokens are verified at `/v1/auth/google/exchange`, which also returns the
canonical account's primary verified wallet when one is linked; partner
wallet proof uses
`/v1/auth/wallet/challenge` plus `/v1/auth/wallet/exchange`, bound to the
service, its exact `siwe_domains`, the app subject, wallet, URI, Base chain,
expiry, and one-use nonce. `/v1/auth/service/bind` binds an app subject after
Expand Down
9 changes: 8 additions & 1 deletion grid_api/routers/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,14 @@ async def exchange_google_identity(
account_id=account_id,
ref=service_auth.new_event_ref("exchange", service["service_id"]),
)
return {"access_token": token, "token_type": "Bearer", "expires_in": 900, "account_id": str(account_id)}
wallets = await identities_svc.verified_wallet_addresses(account_id)
return {
"access_token": token,
"token_type": "Bearer",
"expires_in": 900,
"account_id": str(account_id),
"wallet": wallets[0] if wallets else None,
}


@router.post("/v1/auth/service/bind")
Expand Down
12 changes: 12 additions & 0 deletions grid_api/services/tests/test_native_service_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,18 @@ async def no_value(*_args, **_kwargs):
) == canonical_id
assert await credits.get_balance(UUID(canonical_id)) == 20_000

repeated_google = await accounts_router.exchange_google_identity(
request,
accounts_router.GoogleExchangeForm(
id_token="google-proof-after-wallet-link",
app_subject=app_subject,
),
apikey=key,
authorization=None,
)
assert repeated_google["account_id"] == canonical_id
assert repeated_google["wallet"] == wallet.address.lower()


@pytest.mark.asyncio
async def test_verified_wallet_account_and_balance_are_shared_across_products(
Expand Down
Loading