Auth & Device Registration
Authentication in the boilerplate has two distinct layers that work in sequence:
- Auth0 — proves who the user is (email address, identity)
- Device registration — proves this specific device is authorized to make MPC requests
Both layers are required before any key generation or signing can happen.
The full flow
Sign-in with Auth0
The sign-in flow lives in api/auth/useSignIn.ts. It uses the react-native-auth0 SDK to open the Auth0 Universal Login, gets credentials, registers the user with auth-svc, and stores the user's identity in the auth store.
// api/auth/useSignIn.ts
const { authorize, clearCredentials } = useAuth0();
await authorize({
scope: `openid profile email offline_access ${auth0Config.scope}`,
additionalParameters: { prompt: 'login' },
audience: auth0Config.audience,
});
// Retrieve the access token from the credentials manager
const cred = await auth0Client.credentialsManager.getCredentials();
// Register the user with auth-svc
await APIClient.registerUser({ access_token: cred.accessToken });
// Get user info and save to store
const user = await auth0Client.auth.userInfo({ token: cred.accessToken, tokenType: TokenType.bearer });
signIn({ email: user.email, id: user.sub });
The offline_access scope enables refresh tokens, so returning users are silently re-authenticated on app startup without seeing the login screen again. This is handled in provider/AuthProvider.tsx.
Device registration
Every device that wants to perform MPC operations must be registered with auth-svc. The device is identified by an ECDSA public key stored in the platform's secure hardware:
- iOS — iOS Secure Enclave (Keychain)
- Android — Android Keystore with StrongBox
The device registration challenge-response is handled in libs/secure-key.ts and the registration API calls:
// libs/secure-key.ts
// 1. Create the device keypair in TEE (no-op if it already exists)
SecureKey.createIfNotExistSecureKey(secureKeyAlias);
// 2. MessageSigner — signs all messages from silent-shard-sdk to the cloud node
// The cloud node verifies device identity using this key's public key
export const getMessageSigner = () => {
return SecureKey.createMessageSigner(secureKeyAlias);
};
Learn more about the MessageSigner — how the TEE key is used for transport-level authentication between the SDK and the cloud node.
// Device registration (api/auth/useRegisterDevice.ts)
// 1. Get the device ID (ECDSA public key hex)
const { publicKeyHex } = getSecureKey();
// 2. Fetch a challenge from auth-svc
const { challenge } = await APIClient.getChallenge(publicKeyHex);
// 3. Sign the challenge with the TEE private key
const { sign } = getSecureKey();
const signature = sign(challenge);
// 4. Register the device — auth-svc stores the device_id and links it to the user
await APIClient.registerDevice({ device_id: publicKeyHex, signature });
The device private key never leaves the secure hardware. Only the signature is transmitted. Even if network traffic is intercepted, it is useless without the device.
Silent sign-in on startup
When the app relaunches, provider/AuthProvider.tsx silently checks for existing credentials. If a valid (or refreshable) token exists, the user is restored without seeing the login screen. If not, they are redirected to sign-in.