# Sign-In With Solana ## Introduction Sign In With Solana (SIWS) is a new feature that lets dapps authenticate their users and prove ownership of their addresses. The feature aims to replace the traditionally clunky `connect` + `signMessage` flow with a one-click `signIn` method. Phantom is pioneering support for SIWS alongside the Solana Wallet Standard. The [technical specification](https://github.com/solana-labs/wallet-standard/blob/alpha/packages/core/features/src/signIn.ts) for SIWS is modeled after [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361) (Sign In With Ethereum) but extends beyond it’s capabilities. SIWS shifts the responsibility of message construction from dapps to the wallet, resulting in consistent, user-friendly interfaces and enhanced end-user security. drawing drawing With SIWS, wallets can scrutinize message data to ensure its legitimacy or raise red flags for suspicious activity. Domain binding is a key feature of SIWS, enabling wallets to alert users if a website is impersonating another entity drawing drawing # Specification - `SolanaSignInInput`: ```tsx /** * Optional EIP-4361 Domain. * If not provided, the wallet must determine the Domain to include in the message. */ domain?: string; /** * Optional EIP-4361 Address. * If not provided, the wallet must determine the Address to include in the message. */ address?: string; /** * Optional EIP-4361 Statement. * If not provided, the wallet must not include Statement in the message. */ statement?: string; /** * Optional EIP-4361 URI. * If not provided, the wallet must not include URI in the message. */ uri?: string; /** * Optional EIP-4361 Version. * If not provided, the wallet must not include Version in the message. */ version?: string; /** * Optional EIP-4361 Chain ID. * If not provided, the wallet must not include Chain ID in the message. */ chainId?: string; /** * Optional EIP-4361 Nonce. * If not provided, the wallet must not include Nonce in the message. */ nonce?: string; /** * Optional EIP-4361 Issued At. * If not provided, the wallet must not include Issued At in the message. */ issuedAt?: string; /** * Optional EIP-4361 Expiration Time. * If not provided, the wallet must not include Expiration Time in the message. */ expirationTime?: string; /** * Optional EIP-4361 Not Before. * If not provided, the wallet must not include Not Before in the message. */ notBefore?: string; /** * Optional EIP-4361 Request ID. * If not provided, the wallet must not include Request ID in the message. */ requestId?: string; /** * Optional EIP-4361 Resources. * If not provided, the wallet must not include Resources in the message. */ resources?: string[]; ``` - `SolanaSignInOutput`: ```tsx /** * Account that was signed in. * The address of the account may be different from the provided input Address. */ account: WalletAccount; /** * Message bytes that were signed. * The wallet may prefix or otherwise modify the message before signing it. */ signedMessage: Uint8Array; /** * Message signature produced. * If the signature type is provided, the signature must be Ed25519. */ signature: Uint8Array; /** * Optional type of the message signature produced. * If not provided, the signature must be Ed25519. */ signatureType?: 'ed25519'; ``` # Integrating SIWS SIWS comes with first-class support in both the Solana Wallet Standard and Solana Wallet Adapter libraries. If your dapp makes use of the Solana Wallet Adapter, migration is easy: 1. Download the [attached Phantom build](https://www.notion.so/SIWS-Integration-Guide-bdd43767e32542dc921d63b332939677?pvs=21) 2. Update the necessary [dependencies](https://www.notion.so/SIWS-Integration-Guide-bdd43767e32542dc921d63b332939677?pvs=21) 3. Add this snippet in your `ContextProvider` : ```tsx import { type SolanaSignInInput } from '@solana/wallet-standard-features'; import { verifySignIn } from '@solana/wallet-standard-util'; const autoSignIn = useCallback(async (adapter: Adapter) => { if (!('signIn' in adapter)) return true; // For demo purposes only: The signInInput should // be generated server-side. const input: SolanaSignInInput = { statement: "Welcome to Drip!" }; const output = await adapter.signIn(input); // For demo purposes only: The sign-in verification // should happen server-side. if (!verifySignIn(input, output)) throw new Error('Sign In verification failed!'); return false; }, []); ``` This callback function determines whether a user should be auto-connected (returns `true`) or prompted to sign-in (returns `false`). It does this by: - Checking if the user’s wallet supports the `signIn` feature. - If `signIn` is not available, this callback returns `true` - If `signIn` is available, checking if: - The `SolanaSignInInput` object is prepared - The input is passed into the `signIn` method - The output is verified using the `verifySignIn` [method](https://github.com/solana-labs/wallet-standard/blob/alpha/packages/core/util/src/verify.ts) - If all of the above, the callback returns `false` and the user is prompted to sign-in 4. Pass `autoSignIn` to `WalletProvider` like so: ```tsx ``` # Best Practices - In a production application, both `SolanaSignInInput` generation and `SolanaSignInOutput` verification **should happen** **server-side**. Client-side verification should not be relied upon due to its inherent security flaws. Developers can make use of the asynchronous nature of the `autoSignIn` callback to make a request to the server to obtain SIWS params, and make another request to the server to perform verification of the SIWS input and output. - When generating `SolanaSignInInput`, developers should include as many fields as possible. Each field adds an extra layer of security to protect users against various forms of attacks. Examples of these fields include `nonce`, `chainId`, `issuedAt`, `expirationTime`, and `requestId`. # Reference API - issuedAT — the time at which wahateve, — Phantom currently accepts _+10 min but subject to chagne - In addition to using `nonce` to avoid replay attacks, dapps can also choose to include a unique signature in the `requestId` . Once the wallet returns the signed message, dapps can then verify this signature against the state to add an additional, strong layer of security. # Dependencies These dependencies need to be added to your `package.json`: ```json "@solana/wallet-adapter-base": "0.9.23", "@solana/wallet-adapter-react": "0.15.34", "@solana/wallet-standard-features": "1.1.0", "@solana/wallet-standard-util": "1.1.0", ``` Then, add the following to your `package.json` : ```json "resolutions": { "@solana/wallet-adapter-react": "0.15.34", "@solana/wallet-adapter-base": "0.9.23" }, "overrides": { "@solana/wallet-adapter-react": "0.15.34", "@solana/wallet-adapter-base": "0.9.23" } ``` These configs will be important while testing as some packages like `@solana/wallet-adapter-material-ui` and `@solana/wallet-adapter-react-ui` use older versions of the react and base packages and may cause conflicts. # Full Feature Demo [https://www.loom.com/share/228d2a4820fb44f69fb10c4fb5f2b55a?sid=21478434-bd5f-438d-a526-0b2439b2cde8](https://www.loom.com/share/228d2a4820fb44f69fb10c4fb5f2b55a?sid=21478434-bd5f-438d-a526-0b2439b2cde8) # Reference Implementation Repository: [https://github.com/0xproflupin/sign-in-with-solana](https://github.com/0xproflupin/sign-in-with-solana) App: [https://siws.vercel.app/](https://siws.vercel.app/)