Trying to instrument the full Authorization Code flow with PKCE for a React SPA hitting Genesys Cloud. The goal is to have a single Jaeger trace covering the login redirect, the callback handling, and the final token exchange.
The redirect works fine. The issue is in the handleCallback function. We generate the code_verifier client-side, hash it for the code_challenge, and start an OTel span before the redirect. When the user comes back to the callback URL, we pick up the code parameter and try to exchange it for a token.
Here’s the snippet handling the exchange:
const exchangeToken = async (authCode) => {
const span = tracer.startSpan('gc-pkce-token-exchange');
const codeVerifier = sessionStorage.getItem('codeVerifier');
const payload = new URLSearchParams({
grant_type: 'authorization_code',
code: authCode,
redirect_uri: 'https://myapp.local/callback',
client_id: process.env.REACT_APP_GC_CLIENT_ID,
code_verifier: codeVerifier
});
try {
const response = await fetch('https://api.mypurecloud.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
// Injecting trace context here
'traceparent': span.context().toTraceparent()
},
body: payload
});
const data = await response.json();
span.end();
return data;
} catch (error) {
span.recordException(error);
span.setStatus({ code: SpanStatusCode.ERROR });
span.end();
throw error;
}
};
The request succeeds. We get the access_token and refresh_token. But in Jaeger, the span gc-pkce-token-exchange shows as a root span. It doesn’t link to the initial authorization request span. The traceparent header is definitely being sent.
Genesys Cloud’s OAuth endpoint doesn’t seem to propagate the trace context back in the response headers. Is there a way to force context propagation through the OAuth2 token endpoint, or do I need to manually stitch these spans together using a shared trace ID stored in local storage? The token endpoint is a black box for tracing right now.