I'm using twilio, Symfony 5 with the help of this tuto : https://www.twilio.com/blog/create-group-video-chat-app-symfony-php-twilio-react to create a video chat.
Upon entering the name of the room and launching the visio, I got the following error in the browser's console :
Unable to connect to Room: Invalid Access Token issuer/subject
I understand it's caused because the token generated by the route access_token must not be right.
I've created a normal twilio account then generated the API key, kept account sid, api key sid and api secret on my .env file.
Just in case I recreated a new api key to see if it changed something but didn't.
I've checked the doc for my error (https://www.twilio.com/docs/api/errors/20103) , but the solutions did not solve my problem.
Chat.js
file:
import React, { useState } from "react";
import axios from "axios";
import Video from "twilio-video";
const Chat = () => {
const [roomName, setRoomName] = useState('');
const [hasJoinedRoom, setHasJoinedRoom] = useState(false);
const joinChat = event => {
event.preventDefault();
if (roomName) {
axios.post('/access_token', { roomName }, ).then((response) => {
console.log('RESPONSE: ');
console.log(response.data.token);
connectToRoom(response.data.token);
setHasJoinedRoom(true);
setRoomName('');
}).catch((error) => {
console.log(error);
})
} else {
alert("You need to enter a room name")
}
};
const connectToRoom = (token) => {
const { connect, createLocalVideoTrack } = Video;
let connectOption = { name: roomName };
connect(token, connectOption).then(room => {
console.log(`Successfully joined a Room: ${room}`);
const videoChatWindow = document.getElementById('video-chat-window');
createLocalVideoTrack().then(track => {
videoChatWindow.appendChild(track.attach());
});
room.on('participantConnected', participant => {
console.log(`Participant "${participant.identity}" connected`);
participant.tracks.forEach(publication => {
if (publication.isSubscribed) {
const track = publication.track;
videoChatWindow.appendChild(track.attach());
}
});
participant.on('trackSubscribed', track => {
videoChatWindow.appendChild(track.attach());
});
});
}, error => {
console.error(`Unable to connect to Room: ${error.message}`);
});
};
return(
<div className="container">
<div className={"col-md-12"}>
<h1 className="text-title">Symfony React Video Chat</h1>
</div>
<div className="col-md-6">
<div className={"mb-5 mt-5"}>
{!hasJoinedRoom && (
<form className="form-inline" onSubmit={joinChat}>
<input type="text" name={'roomName'} className={"form-control"} id="roomName"
placeholder="Enter a room name" value={roomName} onChange={event => setRoomName(event.target.value)}/>
<button type="submit" className="btn btn-primary">Join Room</button>
</form>
)}
</div>
<div id="video-chat-window"/>
</div>
</div>
)
};
export default Chat;
TokenController
file to generate user's token :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Twilio\Jwt\AccessToken;
use Twilio\Jwt\Grants\VideoGrant;
class TokenController extends AbstractController
{
/**
* @Route("/token", name="token")
*/
public function index()
{
return $this->render('token/index.html.twig', [
'controller_name' => 'TokenController',
]);
}
/**
* @param Request $req
* @return \Symfony\Component\HttpFoundation\JsonResponse
* @Route("access_token", name="access_token", methods={"POST"})
*/
public function generateToken(Request $req) {
$accountSid = getenv('ACCOUNT_SID');
$apiKeySid = getenv('API_SID');
$apiKeySecretSid = getenv('API_SECRET');
$identity = uniqid();
$roomName = json_decode($req->getContent());
$token = new AccessToken(
$accountSid,
$apiKeySid,
$apiKeySecretSid,
3600,
$identity
);
$grant = new VideoGrant();
$grant->setRoom($roomName->roomName);
$token->addGrant($grant);
return $this->json(['token' => $token->toJWT()], 200);
}
}
And this line in the **app.js**
:
ReactDOM.render(<Chat/>, document.getElementById("root"));
With the proper imports.
UPDATE
Solution found! Thanks for the help !
getenv() method was the issue.
I now inject my .env info in my controller as parameters as follow :
services.yaml
parameters:
app.env.ACCOUNT_SID: '%env(resolve:ACCOUNT_SID)%'
app.env.API_KEY: '%env(resolve:API_KEY)%'
app.env.API_SECRET: '%env(resolve:API_SECRET)%'
And recover them in the controller
Controller to recover the data
public function somename() {
$sid = $this->getParameter('app.env.ACCOUNT_SID');
$apiKey = $this->getParameter('app.env.API_KEY');
$apiSecret = $this->getParameter('app.env.API_SECRET');
$identity = uniqid();
$token = new AccessToken(
$sid,
$apiKey,
$apiSecret,
3600,
$identity
);
}
And works like a charm