Skip to content

MQTT over WebSocket Signature Version 4 http/1.1 403

0

I have tried everything I found online since the mid 2010s, but nothing seems to work.

I have an IoT Thing that works pretty well over MQTT. I am now trying to connect via web socket to the same Thing.

This is the Policy for that Thing:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iot:Publish",
        "iot:Receive",
        "iot:PublishRetain"
      ],
      "Resource": "arn:aws:iot:eu-west-1:279332907237:topic/sdk/test/dart"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "arn:aws:iot:eu-west-1:279332907237:topicfilter/sdk/test/dart"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:GetThingShadow",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:DeleteThingShadow",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:UpdateThingShadow",
      "Resource": "*"
    }
  ]
}

This is how I create the Signature v4 with my IAM User's AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY:

const AWSSigV4Signer signer = AWSSigV4Signer();
    // Create the signing scope and HTTP request
    final AWSCredentialScope scope = AWSCredentialScope(
      region: region,
      service: AWSService.iot,
    );
    final AWSHttpRequest request = AWSHttpRequest(
      method: AWSHttpMethod.get,
      uri: Uri(scheme: 'wss', host: endpoint, path: 'mqtt', port: 443),
    );

    const ServiceConfiguration serviceConfig = ServiceConfiguration(
      omitSessionToken: true,
      signBody: true,
    );

    const Duration expiration = Duration(seconds: 3600);

    // Sign and send the HTTP request
    final Uri signedRequest = await signer.presign(
      request,
      credentialScope: scope,
      serviceConfiguration: serviceConfig,
      expiresIn: expiration,
    );

... which outputs wss://a2eqw4se8i5px2-ats.iot.eu-west-1.amazonaws.com:443/mqtt?X-Amz-Date=20260127T191558Z&X-Amz-SignedHeaders=host&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<THIS_IS_MY_AWS_ACCESS_KEY_ID>%2F20260127%2Feu-west-1%2Fiot%2Faws4_request&X-Amz-Expires=3600&X-Amz-Signature=7d21116970f7cc17eb025648413628cf6a86ce73dca15f54ea6cdf1a3d5060f3

The MQTT client under the hood tries to establish the handshake as follows:

GET /mqtt?X-Amz-Date=20260127T192347Z&X-Amz-SignedHeaders=host&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=<THIS_IS_MY_AWS_ACCESS_KEY_ID>/20260127/eu-west-1/iot/aws4_request&X-Amz-Expires=3600&X-Amz-Signature=3fa6c9ecd5173916e58b13018ea9fb6fa8d43d71efe084d9e9457ac5ca900ce7 HTTP/1.1 
Host: a2eqw4se8i5px2-ats.iot.eu-west-1.amazonaws.com:443
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: bXF0dC0xNzY5NTQxODU5MzI2
Sec-WebSocket-Protocol: mqtt
Sec-WebSocket-Version: 13

... which returns

HTTP/1.1 403 Forbidden
content-type: application/json
content-length: 72
date: Tue, 27 Jan 2026 19:22:09 GMT
x-amzn-RequestId: f66bc55a-f728-59fa-4a86-ff32f45e2d50
connection: keep-alive
x-amzn-ErrorType: ForbiddenException:

{"message":"Forbidden","traceId":"f66bc55a-f728-59fa-4a86-ff32f45e2d50"}

I suspect this has to do with permissions, but everything seems to be in order? I must also say, that documentation to cover this case scenario is virtually non existent. I have found some generic docs here here and here but nothing seems strictly related or explanatory

EDIT: I have been struggling the whole day with this. What I have done:

  • created a new IAM user
  • provided both Root, and the new IAM user with all the necessary IoT permissions
  • provided all IoT related permissions to my IAM group and role
  • in IoT Core, created a Role Alias
  • tried all possible combinations of the above
  • added the below trusted relationship to my Thing Role
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "iot.amazonaws.com",
                "AWS": [
                    "arn:aws:iam::279332907237:user/IoT",
                    "arn:aws:iam::279332907237:root"
                ]
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Nothing seems to be working.

4 Answers
0

That AI generated answer is not very helpful.

  • "Verify that your domain configuration supports MQTT_WSS protocol": you mean AWS' domain? I even lined this
  • "Update your policy to explicitly allow WebSocket connections": which policies are we talking about?
  • "Consider using IAM user credentials instead of root credentials": if it doesn't work with root, why should I waste my time on a new IAM user?
  • "Verify that the date in your signature is correct (your example shows 2026, which might be causing validation issues if it's too far in the future).": that date is auto generated, and correspond to the current time.

Is there a real person I can talk to?! PLEASE!

answered 9 months ago

0

Edit: I have updated the question with the policy I am using right now. I have created a new IAM user for IoT, with its own access key pair, but I still get 403. @Gary Mclean I have reviewed the samples you sent me yesterday, but the implementation is pretty much the same. Can you please advise further?

answered 9 months ago

-1

Does any info here help? https://github.com/aws/aws-iot-device-sdk-java-v2/tree/main/samples/Mqtt

Your using MQTTv5? As apposed to v3?

EXPERT

answered 9 months ago

  • Hi Gary, thanks for your help. I'll take a look a those samples asap, though at first glance my implementation (it's Dart) is pretty similar to the one in there. Are you implying that it's not a policy/IAM issue? The package I'm using is called "mqtt5", though the handshake is made via Dart's built-in http client -- the request is in my question, above

-1

Based on the information provided, it appears you're trying to connect to AWS IoT Core using MQTT over WebSocket with Signature Version 4 authentication, but receiving a 403 Forbidden error.

Looking at your policy and setup, I can identify a few potential issues:

  1. Your policy doesn't explicitly include permissions for WebSocket connections. While you have "iot:Connect" permission with a wildcard resource, AWS IoT Core treats MQTT over WebSocket connections differently from direct MQTT connections.

  2. When using MQTT over WebSocket (MQTT_WSS), you need to ensure that your domain configuration supports this protocol. AWS IoT supports different application protocols including SECURE_MQTT (MQTT over TLS), MQTT_WSS (MQTT over WebSocket), HTTPS, and DEFAULT.

  3. You're using root user credentials for signing, which is not recommended for security reasons. It's better to use IAM user credentials or, preferably, temporary credentials from AWS STS.

To resolve this issue, try the following:

  1. Verify that your domain configuration supports MQTT_WSS protocol.

  2. Update your policy to explicitly allow WebSocket connections. You might need to add specific permissions for WebSocket endpoints.

  3. Consider using IAM user credentials instead of root credentials.

  4. Double-check your signature generation process, ensuring all required headers and parameters are correctly included.

  5. Verify that the date in your signature is correct (your example shows 2026, which might be causing validation issues if it's too far in the future).

The 403 Forbidden error typically indicates a permissions issue, suggesting that either your signature is invalid or your policy doesn't grant the necessary permissions for the action you're attempting.
Sources
Permissions and policies - AWS IoT Core
UpdateDomainConfiguration - AWS IoT
CreateDomainConfiguration - AWS IoT

answered 9 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.