[Problem/Question]
We have a chat in a react app which uses and as described in your examples.
The provider uses a custom SessionHandler to provide the ability to refresh the token, but after some time (can’t really say how many minutes) when the sessionHandler.onSessionTokenRequired
is called and generates a new token which is than resolve(newToken)
then we’re seeing server 500 errors from the sdk to the sendbird server:
https://api-e91a7eaa-412b-43eb-a504-b2b621c6986e.sendbird.com/v3/users/MY_USER_ID/session_key
// Obviously MY_USER_ID is a real user ID.
In addition, the Uncaught (in promise) SendbirdError: This session token is invalid.
seems to be coming from within the sendbird package and i couldn’t find how to catch this error…
Here’s how the provider looks like:
function ChatProvider({ children }) {
const dispatch = useDispatch();
const [token, setToken] = useState();
const state = useSelector((state) => state.toJS());
const userId = state.global?.portalUser;
const [channels, setChannels] = useState();
const authService = useMemo(() => {
return AuthService.getInstance()
}, []);
const issueSessionToken = async () => {
if (!authService?.hasValidToken()) {
return new Error('No Valid Token');
}
return new RequestHelper()
.sendRequest('GET', '/v2/chat/accessToken')
.then((res) => {
if (res.status === 'success' && res.data?.accessToken !== '') {
const token = res.data;
setToken(token);
return token;
} else {
console.error(
'something went wrong trying to get chat access token',
res
);
}
})
.catch((err) => {
console.error('Error trying to get chat access token', err);
return err;
});
};
useEffect(() => {
issueSessionToken();
}, []);
useEffect(() => {
if (!token || !authService?.hasValidToken() || channels) {
return;
}
function getChannels() {
new RequestHelper()
.sendRequest('GET', '/v2/chat/channels')
.then((res) => {
setChannels(res.data.channels)
dispatch({
type: CHAT_SET_CHANNELS,
payload: res.data.channels ?? [],
});
})
.catch((err) => {
console.error('Error trying to get channels for coach', err);
});
}
getChannels();
}, [token]);
const configureSession = () => {
const sessionHandler = new SessionHandler();
sessionHandler.onSessionTokenRequired = async (resolve, reject) => {
const newToken = await issueSessionToken();
if(newToken instanceof Error){
reject('Invalid token');
} else if (newToken) {
resolve(newToken);
} else {
reject('Invalid token');
}
};
return sessionHandler;
};
const isValidSession = useMemo(() => {
return token && userId && authService?.hasValidToken();
}, [token, userId]);
return isValidSession ? (
<SendbirdProvider
appId={config.sendbirdAppId}
userId={userId}
accessToken={token.accessToken}
configureSession={configureSession}
isVoiceMessageEnabled={true}
isMessageReceiptStatusEnabledOnChannelList={true}
isTypingIndicatorEnabledOnChannelList={true}
colorSet={{
'--sendbird-light-primary-500': '#286345',
'--sendbird-light-primary-400': '#286345',
'--sendbird-light-primary-300': '#286345',
'--sendbird-light-primary-200': '#286345',
'--sendbird-light-primary-100': '#286345',
}}
config={{
logLevel:
process.env.REACT_APP_ENV === 'production'
? ['error']
: ['warning', 'error'],
}}
>
{children}
<SendbirdListener />
</SendbirdProvider>
) : (
<div className="chat-info-pane">
<Spinner />
</div>
);
}
The Listener component looks like this:
const SendbirdListener = ({onReconnectionFailed}) => {
const dispatch = useDispatch();
const sendbirdGlobalStore = useSendbirdStateContext();
const sdkInstance = sendbirdSelectors.getSdk(sendbirdGlobalStore);
const updateUnreadCount = (channel) => {
const { url, unreadMessageCount } = channel;
dispatch({
type: CHAT_UPDATE_CHANNELS_UNREAD_COUNT,
payload: { channelId: url, unreadMessageCount },
});
};
useEffect(() => {
const id = generateUid();
let channelHandlerConstructor, connectionHandler;
if (sdkInstance?.groupChannel?.addGroupChannelHandler) {
channelHandlerConstructor = {
onChannelChanged: (channel) => {
updateUnreadCount(channel);
},
};
const channelHandler = new GroupChannelHandler(channelHandlerConstructor);
sdkInstance.groupChannel.addGroupChannelHandler(id, channelHandler);
}
return () => {
if (sdkInstance?.groupChannel?.removeChannelHandler) {
sdkInstance.groupChannel.removeChannelHandler(id);
}
};
}, [sdkInstance]);
return <></>;
};
export default SendbirdListener;
The chat itself looks like this:
function Chat(){
return <SBConversation
channelUrl={currentChannelUrl}
disableMarkAsRead={true}
showSearchIcon={false}
animatedMessage={true}
renderChannelHeader={() => <div />}
reconnectOnIdle={false}
/>
}
// If problem, please fill out the below. If question, please delete.
[UIKit Version]
“@sendbird/chat”: “^4.9.6”,
“@sendbird/uikit-react”: “^3.6.5”,
[Reproduction Steps]
// Please provide reproduction steps and, if possible, code snippets.
[Frequency]
every time
[Current impact]
high impact, expired sessions are crashing the app