I am using pusher-js in react. My frontend is served at app.xxx.com and my backend is served at api.xxx.com. We have a private notification websocket channel to push notiifcations through app.xxx.com. What i'm trying to achieve is using the auth endpoint on backend. But no matter what i do, pusher will always request to the base URL of frontend plus auth endpoint. In my case it will be https://app.xxx.com/broadcasting/auth but i want it to be https://api.xxx.com/broadcasting/auth. What should i do? Here's my pusher config:
pusher = new Pusher(APP_ID, {
httpHost: process.env.REACT_APP_WS_HOST,
authEndpoint: '/broadcasting/auth',
auth: {
params: {
id: userData.id,
},
headers: {
'X-CSRF-Token': '{{ csrf_token() }}'
}
},
cluster: 'ap2',
wsHost: process.env.REACT_APP_WS_HOST,
wsPort: 6001,
wssPort: 6001,
forceTLS: true,
})
The value of process.env.REACT_APP_WS_HOST is api.xxx.com
UPDATE:
I even tried adding an authHost key but nothing changed.
You should be able to use the full URL to the endpoint:
authEndpoint: 'https://api.xxx.com/broadcasting/auth'
Related
I run Laravel 9 app with :
vue 3.2.37
vite 2.9.15
pusher/pusher-php-server 7.0
laravel-echo 1.14.0
All it's work nice on localhost, but on server I have this two events in devtools->network->ws when it try to connect to the channel :
1st : {"event":"pusher:connection_established","data":"{\"socket_id\":\"137307.1921357\",\"activity_timeout\":120}"}
and the 2nd : {"event":"pusher:error","data":{"code":4009,"message":"Connection not authorized within timeout"}}
I have already enable Authorised Connections in my Pusher App settings but I don't know from where this unauthorized error come. It occured just on server side, on localhost I have a subscribed event and there is a different between sockets shown in dev tools on localhost and on server :
localhost : two sockets are shown : ws://localhost:3000/ and wss://ws-eu.pusher.com/app/App_key?protocol=7&client=js&version=7.4.0&flash=false
but on server there is just one : wss://ws-eu.pusher.com/app/App_key?protocol=7&client=js&version=7.4.0&flash=false
bootstrap.js
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
wsPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 80,
wssPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 443,
forceTLS: true, // (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
disableStats: true,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
enabledTransports: ['ws', 'wss'],
//authEndpoint: "https://support.demkit.fr/broadcasting/auth",
encrypted: true,
});
.env :
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=1******
PUSHER_APP_KEY=6******
PUSHER_APP_SECRET=8*********
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME=https
PUSHER_APP_CLUSTER=eu
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
channels.php
Broadcast::channel('messages.{RoomId}', function ($user, $RoomId) {
//if(Auth::check())
//return ['id' => $RoomId];
return true; // I tried to return all time true to get authorization but it doesn't work :(
});
The error is occuring because your client is not subscribing to a private or presence channel within the timeout. When authorized connections are enabled then any connection that does not subscribe to such a channel will be terminated. https://pusher.com/docs/channels/using_channels/authorized-connections/
Either turn off this setting or subscribe to a private/presence channel to resolve.
Slution
I resolved this issue by adding customize the authorization endpoint check Customizing The Authorization Endpoint
docs from laravel
web.php :
Route::post('/pusher/user-auth', [PusherController::class, 'pusherAuth']);
PusherController :
/**
* Authenticates logged-in user in the Pusher JS app
* For private channels
*/
public function pusherAuth(Request $request)
{
$user = auth()->user();
$socket_id = $request['socket_id'];
$channel_name =$request['channel_name'];
$key = config('broadcasting.connections.pusher.key');
$secret = config('broadcasting.connections.pusher.secret');
$app_id = config('broadcasting.connections.pusher.app_id');
if ($user) {
$pusher = new Pusher($key, $secret, $app_id);
$auth = $pusher->socketAuth($channel_name, $socket_id);
return response($auth, 200);
} else {
header('', true, 403);
echo "Forbidden";
return;
}
}
and the bootstrap file :
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
wsPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 80,
wssPort: 443, //import.meta.env.VITE_PUSHER_PORT ?? 443,
forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
disableStats: true,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
enabledTransports: ['ws', 'wss'],
authEndpoint: "/pusher/user-auth", // this is the new endpoint for auth
encrypted: true,
});
and finaly don't froget to change the BROADCAST_DRIVER in .env file to pusher not log
I am trying to send cross origin request to get access token on my React spa app localhost.
I got the first 'Access-Control-Allow-Origin' error, to solve it I defined proxy to webpack.
When I run the code block below, I get 400 bad request errors.
Proxy code
'/payment': {
target: 'https://apitest.domain.com',
changeOrigin: true,
secure: false,
pathRewrite: { '^/payment': '' },
}
-------------------
async getPaymentAccessToken() {
const msg = await request<PaymentAccessTokenResponse>(`/payment/accesstoken/get`, {
method: 'POST',
prefix: undefined,
credentials: 'include',
headers: {
client_id: this.client.client_id,
client_secret: this.client.client_secret,
'Ocp-Apim-Subscription-Key': this.client['payment-Subscription-Key'],
'Merchant-Serial-Number': this.client['Merchant-Serial-Number']!,
},
});
return msg;
}
{"error":"invalid_request","error_description":"AADSTS9002326:
Cross-origin token redemption is permitted only for the 'Single-Page
Application' client-type.\r\nTrace ID:
0c7f2993-b612-434d-9cee-244e88f51600\r\nCorrelation ID:
45d80262-c77f-487b-a95b-4566c736e1bc\r\nTimestamp: 2022-06-07
19:14:30Z","error_codes":[9002326],"timestamp":"2022-06-07
19:14:30Z","trace_id":"0c7f2993-b612-434d-9cee-244e88f51600","correlation_id":"45d80262-c77f-487b-a95b-4566c736e1bc","error_uri":"https://login.windows.net/error?code=9002326"}
Make sure Azure app is registered for SPA platform. You can refer Microsoft official doc
This should solve the issue.
check more config options and samples here
I'm trying to get a mqtt connection on my browser with JS
I'm following this tutorial: https://emqx.medium.com/use-websocket-to-connect-to-mqtt-broker-9e7baf1aa773
So I've got this:
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js" type="text/javascript"></script>
<script>
// Globally initializes an mqtt variable
const clientId = 'mqttjs_' + Math.random().toString(16).substr(2, 8)
const host = 'ws://broker.***.***.com:9883'
const options = {
keepalive: 60,
clientId: clientId,
username: '***',
password: '***',
protocolId: 'MQTT',
protocolVersion: 4,
clean: true,
reconnectPeriod: 1000,
connectTimeout: 30 * 1000,
will: {
topic: 'WillMsg',
payload: 'Connection Closed abnormally..!',
qos: 0,
retain: false
},
}
console.log('Connecting mqtt client')
const client = mqtt.connect(host, options)
client.on('connect', () => {
console.log('Client connected:' + clientId)
// Subscribe
})
</script>
And in my browser I've got this error:
After some research, some people say that need to use certificate: https://github.com/eclipse/paho.mqtt.javascript/issues/187
So, I've got this :
<script src="../browserMqtt.js"></script>
<script src="https://unpkg.com/mqtt/dist/mqtt.min.js"></script>
<script>
var options = {
keyPath: '../credentials/client-key.pem',
certPath: '../credentials/client-cert.pem',
rejectUnauthorized : false,
ca: ['../credentials/a-cert.pem'],
protocolId: 'MQTT',
username: '***',
password: '***',
clientId: 'mqttjs_' + Math.random().toString(16).substr(2, 8)
};
var client = mqtt.connect('ws://broker.***.***.com:9883',options);
client.on('connect', function(){
console.log('Connected');
});
</script>
I've got the same error in browser ...
The broker conguration for mosquitto, it's like this :
allow_anonymous false
password_file /mosquitto/config/passwd
#TCP
listener 1883
socket_domain ipv4
#SSL
listener 8883
socket_domain ipv4
cafile /mosquitto/config/tls/ca/ca-cert.pem
certfile /mosquitto/config/tls/server/server-cert.pem
keyfile /mosquitto/config/tls/server/server-key.pem
tls_version tlsv1.2
socket_domain ipv4
#WSS
listener 9883
socket_domain ipv4
protocol websockets
cafile /mosquitto/config/tls/ca/ca-cert.pem
certfile /mosquitto/config/tls/server/server-cert.pem
keyfile /mosquitto/config/tls/server/server-key.pem
tls_version tlsv1.2
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
log_timestamp_format %Y-%m-%dT%H:%M:%S
log_type all
I can't understand how can I solve it ? Thanks for your help
You can't use client side certs in the browser to authenticate the client (unless you load them into the browsers keystore, but even then I'm not convinced it will work unless there is only one cert/key for the browser to pick as javascript code won't normally prompt the user to pick the right one).
Also loading client certs over http from the server totally defeats the point of using a client cert as anybody can download them.
You need to remove all of the following from the options
keyPath: '../credentials/client-key.pem',
certPath: '../credentials/client-cert.pem',
rejectUnauthorized : false,
ca: ['../credentials/a-cert.pem'],
protocolId: 'MQTT',
Because the paths are meaningless in the browser (and for the reasons I mentioned earlier)
You should also be starting your broker URL with wss:// to make it clear you are trying to connect over secure WebSockets.
I am creating proxy API gateway to non-public S3 bucket using CDK.
The S3 bucket contains html, javascript, and css files.
I created an api using CDK like this:
const api = new apigw.RestApi(this, 'Test-Web')
api.root
.addResource('{file}')
.addMethod('GET', new apigw.AwsIntegration({
service: 's3',
integrationHttpMethod: 'GET',
path: `${bucket.bucketName}/{file}`,
options: {
credentialsRole: role,
requestParameters: {
'integration.request.path.file': 'method.request.path.file'
},
integrationResponses: [{
statusCode: '200'
}]
}
}), {
requestParameters: {
'method.request.path.file': true
},
methodResponses: [{
statusCode: '200'
}]
})
It works fine, but has a problem. The content type of the response is always set to application/json. I could see that the content type of integration responses (responses from S3) varies from text/html to text/css, application/javascript depending on the file.
How can I set this API to return correct content type on each file by passing the same content type header value of integration response to method response? Best if I can pass the content-type header from S3 as it already returns correctly.
CDK documentation is not great. I managed to find a solution:
I had to add responseParameters in integrationResponses to set Content-Type header from S3 to API gateway response. Please see below, especially the line marked with <<<--.
api.root
.addResource('{file}')
.addMethod(
'GET',
new apigw.AwsIntegration({
service: 's3',
integrationHttpMethod: 'GET',
path: `${bucket.bucketName}/{file}`,
options: {
credentialsRole: role,
requestParameters: {
'integration.request.path.file': 'method.request.path.file'
},
integrationResponses: [{
statusCode: '200',
selectionPattern: '2..',
responseParameters: {
'method.response.header.Content-Type': 'integration.response.header.Content-Type' // <<<--
},
}, {
statusCode: '403',
selectionPattern: '4..'
}]
}
}), {
requestParameters: {
'method.request.path.file': true
},
methodResponses: [{
statusCode: '200',
responseParameters: {
'method.response.header.Content-Type': true // <<<--
}
}, {
statusCode: '404'
}]
})
I am very much new to JavaScript and XMPP and need to implement Socks5 to transfer files with Strophe.js
when i call the method below:
sendS5BInitiation: function (from ,to, sid, jid, host, port, cb) {
var iq = $iq({
from: from,
id: sid,
to: to,
type: 'set'
}).c('query', {
xmlns: 'http://jabber.org/protocol/bytestreams',
sid: sid ,
mode: "tcp"
}).c('streamhost',{
jid: jid,
host: host,
port: port
});
connection.sendIQ(iq,onSuccess,onError,60*1000);
}
I get 406 error as
<iq id="4023b2c8" to="dummy#myserver/4023b2c8" from="xyz#myserver/Spark 2.6.3" type="error"><query xmlns="http://jabber.org/protocol/bytestreams" sid="4023b2c8" mode = "tcp"><streamhost jid="dummy#myserver" host="182.148.1.200" port="7777"/></query><error code="406" type="MODIFY"><not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>
Please help me to get out of this problem.