# Content Security Policy (CSP) Source: https://docs.reown.com/advanced/security/content-security-policy ## Overview A Content Security Policy (CSP) is a security feature that helps protect web applications from various attacks like Cross-Site Scripting (XSS), clickjacking, and data injection. By specifying allowed content sources, CSPs minimize the risk of executing malicious content on your site. ## CSP Guidance ### AppKit The following is a **partial CSP** that covers WalletConnect's libraries and services for [AppKit](https://docs.walletconnect.com/appkit/overview). Note that **you may need to define additional sources based on your application's requirements**. ``` default-src 'self'; script-src 'self'; style-src https://fonts.googleapis.com; img-src * 'self' data: blob: https://walletconnect.org https://walletconnect.com https://secure.walletconnect.com https://secure.walletconnect.org https://tokens-data.1inch.io https://tokens.1inch.io https://ipfs.io https://cdn.zerion.io; font-src 'self' https://fonts.gstatic.com https://fonts.reown.com; connect-src 'self' https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org https://keys.walletconnect.com https://keys.walletconnect.org https://notify.walletconnect.com https://notify.walletconnect.org https://echo.walletconnect.com https://echo.walletconnect.org https://push.walletconnect.com https://push.walletconnect.org wss://www.walletlink.org https://cca-lite.coinbase.com; frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org; Cross-Origin-Opener-Policy: same-origin-allow-popups; ``` You may need to list the RPC endpoints used by blockchain networks you have enabled (e.g. via the [`@wagmi/chains` package](https://wagmi.sh/core/api/chains)) as part of your `connect-src` definition. For a full of list of RPC sources used by `wagmi/viem`, please refer to [Viem's chain definitions](https://github.com/wevm/viem/tree/main/src/chains/definitions). **Cross-Origin-Opener-Policy for Social Login Security**: The `Cross-Origin-Opener-Policy: same-origin-allow-popups` header is essential when using AppKit's social login features (Google, X, GitHub, Discord, Apple, Facebook, Farcaster). This header helps prevent tabnabbing attacks during OAuth flows by controlling how popup windows can interact with your application. Without this header, malicious sites could potentially hijack the authentication flow and redirect users to phishing pages. ## Testing and Deploying Your CSP ### Test Your CSP in a Staging Environment Run through your standard user flows in a staging environment with CSP enforcement. This may include connecting to browser extension wallets, transacting, logging out, etc. Directives may need updates after SDK upgrades. Always test your CSP again before deploying updates to production. ### Using Report-Only Mode Use the `Content-Security-Policy-Report-Only` header, which sends violation reports without enforcing policies. This helps assess the impact of CSP changes without affecting functionality. ### Deployment First deploy your CSP in `report-only` mode. After validation, migrate to `Content-Security-Policy` for enforcement. ### Monitoring Configure `report-uri` or `report-to` to receive violation reports and set up a monitoring dashboard for review. # Security Information Source: https://docs.reown.com/advanced/security/security-information Security is not just a feature but a fundamental aspect of Reown's architecture. The infrastructure has undergone multiple rounds of third-party security reviews, audits, penetration testing, and threat modeling to ensure the highest standards of protection. Security is viewed as a continuously evolving discipline, with regular system audits to identify and address potential vulnerabilities. ## AppKit - Embedded Wallet Key Management ### Architecture and Custody AppKit Embedded wallets enable applications to provide end-users with a quick onboarding experience by provisioning a non-custodial wallet through social login or email wallets. While the implementation varies per network, Reown relies on a SOC 2 Type 2 compliant third-party vendor for key management. The vendor's [security overview](https://magic.link/docs/home/security/product-security) and [list of audits](https://magic.link/docs/home/security/security-compliance) are available in their documentation. For a subset of EVM Networks, gas abstraction functionality requires deploying a Smart Account on behalf of the end-user. In this case, the key management provider acts as a signer for this Smart Account. Reown relies on a third-party vendor for the Smart Account implementation. The [Smart Account implementation audits](https://docs.safe.global/smart-account-audits) are available in their documentation. ### Key Export Reown enables end-users to export their keys when needed. ### Audits Both the key management vendors and Smart Account vendors have undergone multiple audits (see links above). The integration of the key management provider into AppKit has been audited by Halborn. The complete audit report is available [here](https://drive.google.com/file/d/1LQ6BkcI4PHs_FKAzpCRMqwD--rq6uOy6/view). ## WalletKit ### Architecture WalletKit provides an end-to-end encrypted solution for wallets to connect to applications and sign messages/transactions. As an open-source SDK, it supports multiple transport methods, from WebSockets to Universal Links. ### Handshake & End-to-End Encryption For a detailed overview of the handshake and end-to-end encryption protocol, refer to the [technical specification](https://specs.walletconnect.com/2.0/specs/clients/sign/session-proposal). ### Audits WalletKit, including its encryption stack, was audited by Trail of Bits. The audit report is available [here](https://github.com/trailofbits/publications/blob/master/reviews/2023-03-walletconnectv2-securityreview.pdf). This comprehensive security review covered the source code and included a lightweight Threat Model covering upstream and downstream dependencies. The broader WalletConnect system underwent Threat Modeling by Spearbit. The threat model is available [here](https://drive.google.com/file/d/1QpPSLvCEMunaYHHBPN0g6kYd39uFxpPk/view). ### Dependencies WalletKit's design philosophy prioritizes minimizing third-party dependencies to reduce the attack surface area. ## Third-Party Reviews The security infrastructure of Reown has undergone multiple rounds of audits by independent security auditing firms, including Trail of Bits, Halborn, and Spearbit. These audits cover both AppKit and WalletKit, along with a comprehensive company-wide Threat Model. | Audit Scope | Auditor | Report | | ---------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------- | | WalletConnect Comprehensive Threat Model | Spearbit | [View Report](https://drive.google.com/file/d/1QpPSLvCEMunaYHHBPN0g6kYd39uFxpPk/view) | | AppKit Embedded Wallet Integration Pentest | Halborn | [View Report](https://drive.google.com/file/d/1LQ6BkcI4PHs_FKAzpCRMqwD--rq6uOy6/view) | | WalletKit Security Review & Lightweight Threat Model | Trail of Bits | [View Report](https://github.com/trailofbits/publications/blob/master/reviews/2023-03-walletconnectv2-securityreview.pdf) | ## Bug Bounty Program Reown maintains an active bug bounty program to encourage security researchers to responsibly disclose vulnerabilities and help strengthen the systems. For more information, visit the [security text file](https://reown.com/.well-known/security.txt) or the [security page](https://reown.com/security). ## Get in Touch For security-related inquiries, please visit the [security contact page](https://reown.com/security). # Actions Source: https://docs.reown.com/appkit/android/core/actions ## Chains ### Get selected chain You can get selected chain by calling the `getSelectedChain()` on the `AppKit` object. ```kotlin theme={null} AppKit.getSelectedChain() ``` ## AppKit.ModalDelegate ```kotlin theme={null} val appKitModalDelegate = object : AppKit.ModalDelegate { override fun onSessionApproved(approvedSession: Modal.Model.ApprovedSession) { // Triggered when receives the session approval from wallet } override fun onSessionRejected(rejectedSession: Modal.Model.RejectedSession) { // Triggered when receives the session rejection from wallet } override fun onSessionUpdate(updatedSession: Modal.Model.UpdatedSession) { // Triggered when receives the session update from wallet } override fun onSessionExtend(session: Modal.Model.Session) { // Triggered when receives the session extend from wallet } override fun onSessionEvent(sessionEvent: Modal.Model.SessionEvent) { // Triggered when the peer emits events that match the list of events agreed upon session settlement } override fun onSessionDelete(deletedSession: Modal.Model.DeletedSession) { // Triggered when receives the session delete from wallet } override fun onSessionRequestResponse(response: Modal.Model.SessionRequestResponse) { // Triggered when receives the session request response from wallet } override fun onProposalExpired(proposal: Modal.Model.ExpiredProposal) { // Triggered when a proposal becomes expired } override fun onRequestExpired(request: Modal.Model.ExpiredRequest) { // Triggered when a request becomes expired } override fun onConnectionStateChange(state: Modal.Model.ConnectionState) { //Triggered whenever the connection state is changed } override fun onError(error: Modal.Model.Error) { // Triggered whenever there is an issue inside the SDK } } ``` You have set delegate on AppKit to start getting updates from Wallet. ```kotlin theme={null} AppKit.setDelegate(appKitModalDelegate) ``` ## Actions ### Disconnect ```kotlin theme={null} AppKit.disconnect( onSuccess = { /* callback that letting you know that you have successfully disconnected */ }, onError = { error -> /* callback for error while trying to disconnection with a peer */ } ) ``` ### Request ```kotlin theme={null} val requestParams = Modal.Params.Request( method = /* Selected method */, params = /* Method params */, ) AppKit.request( request = requestParams, onSuccess = { /* callback that letting you know that you have successful request */ }, onError = { error -> /* callback for error */ } ) ``` ### Get Active Account Returns the current active account connected via AppKit ```kotlin theme={null} AppKit.getAccount() ``` ### Get Connection type Return information about the type of our connection ```kotlin theme={null} AppKit.getConnectorType() ``` # Components Source: https://docs.reown.com/appkit/android/core/components You can use predefined AppKitComponent and add it in your application. As a view, dialog or modal. ```kotlin theme={null} import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetState import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.compose.material.ModalBottomSheetLayout setContent { val modalSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = true) val coroutineScope = rememberCoroutineScope() val navController = rememberNavController() ModalBottomSheetLayout( sheetContent = { AppKitComponent( shouldOpenChooseNetwork = true | false, closeModal = { coroutineScope.launch { modalSheetState.hide() } ) } ) { // content } } ``` ## Buttons You can add ready made button components to your application ### Web3Button ```kotlin theme={null} import com.reown.appkit.ui.components.button.Web3Button import com.reown.appkit.ui.components.button.ConnectButtonSize import com.reown.appkit.ui.components.button.AccountButtonType import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) Web3Button( state = appKitState, accountButtonType = AccountButtonType.NORMAL || AccountButtonType.MIXED, connectButtonSize = ConnectButtonSize.NORMAL || ConnectButtonSize.SMALL ) } ``` ```xml theme={null} ``` ### Network Button ```kotlin theme={null} import com.reown.appkit.ui.components.button.NetworkButton import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) NetworkButton(state = appKitState) } ``` ```xml theme={null} ``` ### Connect Button ```kotlin theme={null} import com.reown.appkit.ui.components.button.ConnectButton import com.reown.appkit.ui.components.button.ConnectButtonSize import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) ConnectButton( state = appKitState, buttonSize = ConnectButtonSize.NORMAL || ConnectButtonSize.SMALL ) } ``` ```xml theme={null} ``` ### Account Button ```kotlin theme={null} import com.reown.appkit.ui.components.button.AccountButton import com.reown.appkit.ui.components.button.AccountButtonType import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) AccountButton( state = appKitState, buttonSize = AccountButtonType.NORMAL || AccountButtonType.MIXED ) } ``` ```xml theme={null} ``` ### AppKit State AppKitState is an object that ensures communication between your application and the state of the AppKit. #### Create appKitState: NavController is required to create appKitState ```kotlin theme={null} val appKitState = rememberAppKitState(navController) ``` #### AppKitState methods ```kotlin theme={null} appKitState.isOpen ``` returns `StateFlow` whose value is updated depending on whether the appkit component is open ```kotlin theme={null} appKitState.isConnected ``` returns `StateFlow` whose value depends on the active session in AppKit # Kotlin Source: https://docs.reown.com/appkit/android/core/installation Kotlin implementation of AppKit for Android applications. Android Core \ Appkit ### Requirements * Android min SDK 23 * Java 11 ## Installation root/build.gradle.kts: ```gradle theme={null} allprojects { repositories { mavenCentral() maven { url "https://jitpack.io" } } } ``` app/build.gradle.kts ```gradle theme={null} implementation(platform("com.reown:android-bom:$BOM_VERSION")) implementation("com.reown:android-core") implementation("com.reown:appkit") ``` ## ProGuard rules If you encounter issues with minification, add the below rules to your application: ``` -keepattributes *Annotation* -keep class com.sun.jna.** { *; } -keepclassmembers class com.sun.jna.** { native ; *; } -keep class uniffi.** { *; } -dontwarn uniffi.** -dontwarn com.sun.jna.** ``` ## Example Check the Kotlin example ## Test Apps Want to see AppKit in action? Download our sample AppKit apps below and explore what it can do. Enjoy! 😊 * [Android Build (Firebase)](https://appdistribution.firebase.google.com/pub/i/4cf60e7b49f9265e) # Sign In With Ethereum Source: https://docs.reown.com/appkit/android/core/one-click-auth AppKit provides a simple solution for integrating with "Sign In With Ethereum" (SIWE), a form of authentication that enables users to control their digital identity with their Ethereum account. SIWE is a standard also known as [EIP-4361](https://docs.login.xyz/general-information/siwe-overview/eip-4361). ## One-Click Auth One-Click Auth represents a key advancement within WalletConnect v2, streamlining the user authentication process in AppKit by enabling them to seamlessly connect with a wallet and sign a SIWE message with just one click. Connecting a wallet, proving control of an address with an off-chain signature, authorizing specific actions. These are the kinds of authorizations that can be encoded as "ReCaps". ReCaps are permissions for a specific website or dapp that can be compactly encoded as a long string in the message you sign and translated by any wallet into a straight-forward one-sentence summary. WalletConnect uses permissions expressed as ReCaps to enable a One-Click Authentication. ## Configure your AppKit Client To integrate SIWE with AppKit, you need to configure your AppKit client using `Modal.Model.AuthPayloadParams`, which are required to create a SIWE message for the user to sign: ```kotlin theme={null} AppKit.setAuthRequestParams(authPayloadParams) ``` #### Example of AuthRequestParams ```kotlin theme={null} val authParams = Modal.Model.AuthPayloadParams( chains = ["eip155:1", "eip155:137"], domain = "yourDappDomain.com", uri = "https://yourDappDomain.com/login", nonce = //uniqueNonce, statement = "I accept the Terms of Service: https://yourDappDomain.com/", methods = ["personal_sign", "eth_sendTransaction"], resources = null //// Here your dapp may request authorization with ReCaps ) ``` Configuring your AppKit client with Modal.Model.AuthPayloadParams will prioritize authentication requests over regular session proposals. If the wallet supports One-Click Auth, the session will be created and the user will automatically authenticate without needing to send another SIWE request over personal\_sign. If the wallet does not support One-Click Auth, it will fall back to the session proposal. In this case, to authenticate the user, AppKit will send another session request to prove address ownership. To check whether the user has signed a SIWE message, check `onSessionAuthenticateResponse` callback from `AppKit.ModalDelegate`: ```kotlin theme={null} fun onSessionAuthenticateResponse(response: Modal.Model.SessionAuthenticateResponse) { // Triggered when Dapp receives the session authenticate response from wallet if (response is Modal.Model.SessionAuthenticateResponse.Result) { if (response.session != null) { // Authentication successful, session established } else { // Authentication successful, but no session created (SIWE-only flow) } } else { // Authentication request was rejected or failed } } ``` ### Fallback to SIWE Over Session Request If the wallet connecting to your dapp does not support One-Click Auth, the SDK will fallback to the `wc_sessionPropose` method and create a session with the wallet. AppKit will then inform the user that they need to sign a message to prove address ownership. AppKit will send a SIWE request to the wallet, and once the wallet responds with a signed message, use `onSIWEAuthenticationResponse` callback to check the result: ```kotlin theme={null} override fun onSIWEAuthenticationResponse(response: Modal.Model.SIWEAuthenticateResponse) { if (response is Modal.Model.SIWEAuthenticateResponse.Result) { // message and signature } else { //error } } ``` ### Link Mode The latest release of AppKit supports link mode, a low latency mechanism for transporting One-Click Auth requests and session requests over universal links, reducing the need for a WebSocket connection with the Relay. This significantly enhances the user experience when connecting native dApps to native wallets by reducing the latency associated with networking connections, especially when the user has an unstable internet connection.