useServerChallengeReceived
useServerChallengeReceived
is a custom hook that handles mTLS (Mutual TLS) authentication in Kepler apps. This hook manages certificate challenges from servers and provides methods to set client certificates for secure communication.
The following shows how to import the hook.
import { useServerChallengeReceived } from "@amzn/react-native-kepler";
The following shows how to to use the hook.
const { isChallengeReceived, setAuthCert, challengeUrl } = useServerChallengeReceived();
AuthCertParams
If you need to provide authentication certificates as part of your server challenge, use the AuthCertParams
interface to define them.
interface AuthCertParams {
url: string;
clientCert: string;
clientKey: string;
}
Properties
- url - The URL for which to set the certificates
- clientCert - Path to the client certificate file
- clientKey - Path to the client key file
Hook interface definition
The following shows the hook's return type definition.
export const useServerChallengeReceived = (): {
/** Counter that increments when a challenge is received */
isChallengeReceived: number;
/** Function to set authentication certificates */
setAuthCert: (params: AuthCertParams) => void;
/** The URL that initiated the certificate challenge */
challengeUrl: string;
} => {
// ... hook implementation
};
Configuration: Required Assets
Network Security Configuration
To provide rootCA certificates, create a network-config.json
file in your project's assets/raw
directory with the following structure.
{
"networkSecurityConfig": {
"domainConfig": [
{
"domain": {
"name": "127.0.0.1",
"includeSubdomains": true, /* When true, applies to all subdomains */
"certificates": "raw/ca.crt"
}
}
]
}
}
Note: Replace "127.0.0.1"
with your target domain and adjust includeSubdomains
as needed. Setting includeSubdomains
to true
applies the certificate configuration to the main domain and all its subdomains (For example, both example.com
and api.example.com
). Set it to false
to restrict the configuration to only the exact domain specified.
Certificate Files
Place the following certificate files in your application's assets/raw
directory.
/assets/raw/
├── client.crt # Client certificate
├── client.key # Client private key
├── ca.crt # Certificate Authority (CA) certificate
└── network-config.json
The following sample shows a basic mTLS Implementation.
import { useServerChallengeReceived } from "@amzn/react-native-kepler";
import { useEffect, useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";
const SERVER1_URL = "https://vs-ws-test-domain.xyz";
const SERVER2_URL = "https://127.0.0.1:3001";
const CLIENT1_CERT = "/raw/client-cert.pem";
const CLIENT1_KEY = "/raw/client-key.pem";
const CLIENT2_CERT = "/raw/client.crt";
const CLIENT2_KEY = "/raw/client.key";
const getDomainFromURL = (input: string): string => {
if (!input || typeof input !== 'string') {return 'Invalid URL';}
const url = input.trim();
const noProtocol = url.replace(/^(https?:\/\/)?/i, '');
const domainPart = noProtocol.split(/[\/?#]/)[0];
const domain = domainPart.split(':')[0];
const domainRegex = /^([a-zA-Z0-9.-]+\.[a-zA-Z]{2,}|localhost|^\d{1,3}(\.\d{1,3}){3})$/;
return domainRegex.test(domain) ? domain : 'Invalid URL';
};
// State management for responses
const App = () => {
const [response1, setResponse1] = useState(null);
const [response2, setResponse2] = useState(null);
const { isChallengeReceived, setAuthCert, challengeUrl } = useServerChallengeReceived();
const server1Domain = getDomainFromURL(SERVER1_URL);
const server2Domain = getDomainFromURL(SERVER2_URL);
// Function to fetch data
const fetchData = async (serverUrl, setResponse) => {
try {
const response = await fetch(serverUrl, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
const data = await response.json();
setResponse(data);
} catch (error) {
setResponse({ error: "Request failed. Check logs." });
}
};
// Function to set authentication certificates
function setCerts(url) {
try {
if (url === server1Domain) {
setAuthCert({
url: challengeUrl,
clientCert: CLIENT1_CERT,
clientKey: CLIENT1_KEY,
});
} else if (url === server2Domain) {
setAuthCert({
url: challengeUrl,
clientCert: CLIENT2_CERT,
clientKey: CLIENT2_KEY,
});
} else {
console.log("Invalid URL for certificate setup");
}
} catch (error) {
console.error("Failed to set certificates:", error);
}
}
// Handle authentication challenges
useEffect(() => {
if (isChallengeReceived || challengeUrl) {
setCerts(challengeUrl);
}
}, [isChallengeReceived, challengeUrl]);
return (
<View style={styles.container}>
<View style={styles.section}>
<Button title="Fetch from Server 1" onPress={() => fetchData(SERVER1_URL, setResponse1)} />
{response1 && <Text style={styles.response}>Server 1: {JSON.stringify(response1, null, 2)}</Text>}
</View>
<View style={styles.section}>
<Button title="Fetch from Server 2" onPress={() => fetchData(SERVER2_URL, setResponse2)} />
{response2 && <Text style={styles.response}>Server 2: {JSON.stringify(response2, null, 2)}</Text>}
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {backgroundColor: '#16191f', paddingHorizontal: 5, flex: 1, display: 'flex', alignItems: 'center', overflow: 'hidden'},
header: { fontSize: 22, fontWeight: "bold", marginBottom: 20 },
section: { marginVertical: 10, width: "100%", alignItems: "center" },
response: { marginTop: 10, padding: 10, backgroundColor: "#f0f0f0", borderRadius: 5, width: "90%" },
});
export default App;
Last updated: Sep 30, 2025