A React Native (Expo) chat app that integrates Stream Chat for messaging and adds true end‑to‑end encryption (E2EE) with local key generation, secure storage, and message encryption/decryption on device.
- Stream Chat UI and realtime messaging (via
stream-chat-expo
) - E2E encryption: secp256k1 ECDH + HKDF + AES‑256‑GCM
- Local key management using Expo SecureStore
- Key fingerprints for human verification
- Auth + user list + 1:1 chat flows
- Backend integration for registration, login, token issuing, and public key discovery
- Node.js LTS and npm
- Expo (locally via
npx expo
) - iOS Simulator or Android Emulator, or a real device on the same network
- A running backend server from this repo’s
backend
directory (Express + Stream)
Navigation/App.tsx
: navigation, providers, and root screen setupNavigation/context/EncryptionContext.tsx
: app-wide E2E APIs and key lifecycleNavigation/screens/AuthScreen.tsx
: register (with public key), login, connect StreamNavigation/screens/UsersScreen.tsx
: list users, select recipient, logoutNavigation/screens/ChatScreen.tsx
: create/join channel, encrypt on send, decrypt on receiveNavigation/utils/encryption.ts
: low-level crypto helpersNavigation/utils/streamClient.ts
: Stream client instanceNavigation/config/constants.ts
:STREAM_API_KEY
andBACKEND_URL
configuration
- Install dependencies (React Native app)
cd Navigation
npm install
- Configure Stream and Backend
- Open
Navigation/config/constants.ts
and set:- STREAM_API_KEY: your Stream key
- BACKEND_URL: your backend base URL (use your machine IP for real devices)
- Examples are included in the file; uncomment the one that fits your environment.
- Start the backend
- Ensure
STREAM_API_KEY
andSTREAM_API_SECRET
are set in environment variables. - Then in another terminal:
cd ../backend
npm install
npm run dev
(Alternatively, add a start
script in backend/package.json
and run npm start
.)
- Run the app (from
Navigation/
)
npx expo start -c
- Press
a
for Android,i
for iOS, or scan the QR to open on device.
- Key generation: device creates a secp256k1 key pair and stores it in secure storage.
- Registration: client sends only the public key to the backend, which stores it on the user’s Stream profile.
- Sending: sender derives a shared secret with recipient’s public key (ECDH), derives an AES‑GCM key via HKDF, encrypts, and sends JSON
{ciphertext, iv, authTag}
to Stream. - Receiving: recipient fetches the sender’s public key, derives the same AES‑GCM key, and decrypts locally.
- Servers see only ciphertext; private keys never leave the device.
Key APIs (via useRealEncryption()
):
generateKeys(userId)
,loadKeys(userId)
,deleteUserKeys(userId)
,clearKeys()
encryptMessage(message, recipientPublicKey)
decryptMessage(encryptedMessage, senderPublicKey)
getPublicKeyString()
,getKeyFingerprint()
,validatePublicKey(pub)
- Open the app →
Auth
screen
- Register: generates keys and registers public key with the backend.
- Login: obtains a Stream token from backend and connects.
Users
screen
- Pick a user to chat with. A 1:1 channel is created or joined.
Chat
screen
- Message text is encrypted on send and decrypted on receive.
- A small “E2E” indicator shows encrypted messages.
- AppRegistryBinding::startSurface failed. Global was not installed
- Ensure these side-effect imports come first in
Navigation/App.tsx
(very top, before other imports):
- Ensure these side-effect imports come first in
import 'react-native-get-random-values';
- Clear caches and restart Expo:
npx expo start -c
- On some setups, also add:
import 'react-native-url-polyfill/auto';
- Can’t connect to backend from device
- Use your machine’s LAN IP in
config/constants.ts
(notlocalhost
), and ensure both are on the same network.
- Use your machine’s LAN IP in
- Stream errors
- Verify
STREAM_API_KEY
matches your backend’s key/secret pair.
- Verify
npm run start
– start Exponpm run android
/npm run ios
/npm run web
- This project is for educational purposes and demonstrates one E2EE approach. For production, consider key rotation, ephemeral ECDH, device trust, attachments encryption, and robust error handling.
- README covers setup, configuration, run instructions, E2EE overview, and troubleshooting tailored to the
Navigation
app.