mhart / aws4

Signs and prepares Node.js requests using AWS Signature Version 4
MIT License
703 stars 176 forks source link

Some services require the X-Amz-Security-Token not be in the canonical string for signed querystring requests #30

Open txase opened 8 years ago

txase commented 8 years ago

The session token must be added after signing.

txase commented 8 years ago

Ugh, apparently this is service-specific. See the note here: http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html.

When you add the X-Amz-Security-Token parameter to the query string, some services require that
you include this parameter in the canonical (signed) request. For other services, you add this parameter
at the end, after you calculate the signature. For details, see the API reference documentation for that
service.

Maybe this should be an option that can be set? Or, I suppose, users could just append it on after the fact for services that shouldn't have it included in the signing...

mhart commented 8 years ago

@txase which service did you see this with?

(in any case, you're right – you can just add it after signing)

txase commented 8 years ago

IoT, while generating a url to connect to a websocket.

On Tuesday, August 9, 2016, Michael Hart notifications@github.com wrote:

@txase https://github.com/txase which service did you see this with?

(in any case, you're right – you can just add it after signing)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/mhart/aws4/issues/30#issuecomment-238549591, or mute the thread https://github.com/notifications/unsubscribe-auth/AA6vhFfR5x9Iw8i3J6jiY-mrvHGGjOoeks5qeH4ogaJpZM4JfsF3 .

brettstack commented 7 years ago

Working example:

import aws4 from 'aws4'
import mqtt from 'mqtt'
const AWS_IOT_ENDPOINT = 'YOUR_ENDPOINT_ID.iot.us-east-1.amazonaws.com'

function signRequest ({ region, accessKeyId, secretAccessKey }) {
  return aws4.sign({
    host: AWS_IOT_ENDPOINT,
    path: '/mqtt',
    service: 'iotdevicegateway',
    region,
    signQuery: true
  }, {
    accessKeyId,
    secretAccessKey
  })
}

export function getClient ({ region, accessKeyId, secretAccessKey, sessionToken }) {
  // NOTE: IoT does not expect X-Amz-Security-Token to be included in the signature, but it must be added in the path
  const { path } = signRequest({ region, accessKeyId, secretAccessKey })

  const client = mqtt.connect(`wss://${AWS_IOT_ENDPOINT}${path}&X-Amz-Security-Token=${encodeURIComponent(sessionToken)}`)

  return client
}
const client = getClient({ region, accessKeyId, secretAccessKey, sessionToken })

client.on('connect', function () {
  client.subscribe('my-topic')

  window.setInterval(() => {
    client.publish('my-topic', 'Hello mqtt')
  }, 1000)
})

client.on('message', function (topic, message) {
  console.log(message.toString())
})
mhart commented 7 years ago

@brettstack great! thanks for that example.

I think in this case I'll just add a check specifically for iot and not include the security token in the signature (but still add it to the query)

Are there any other services that do this?