twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

README.md (17008B)


      1 aws4
      2 ----
      3 
      4 [![Build Status](https://secure.travis-ci.org/mhart/aws4.png?branch=master)](http://travis-ci.org/mhart/aws4)
      5 
      6 A small utility to sign vanilla Node.js http(s) request options using Amazon's
      7 [AWS Signature Version 4](http://docs.amazonwebservices.com/general/latest/gr/signature-version-4.html).
      8 
      9 If you want to sign and send AWS requests in a modern browser, or an environment like [Cloudflare Workers](https://developers.cloudflare.com/workers/), then check out [aws4fetch](https://github.com/mhart/aws4fetch) – otherwise you can also bundle this library for use [in the browser](./browser).
     10 
     11 This signature is supported by nearly all Amazon services, including
     12 [S3](http://docs.aws.amazon.com/AmazonS3/latest/API/),
     13 [EC2](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/),
     14 [DynamoDB](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/API.html),
     15 [Kinesis](http://docs.aws.amazon.com/kinesis/latest/APIReference/),
     16 [Lambda](http://docs.aws.amazon.com/lambda/latest/dg/API_Reference.html),
     17 [SQS](http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/),
     18 [SNS](http://docs.aws.amazon.com/sns/latest/api/),
     19 [IAM](http://docs.aws.amazon.com/IAM/latest/APIReference/),
     20 [STS](http://docs.aws.amazon.com/STS/latest/APIReference/),
     21 [RDS](http://docs.aws.amazon.com/AmazonRDS/latest/APIReference/),
     22 [CloudWatch](http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/),
     23 [CloudWatch Logs](http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/),
     24 [CodeDeploy](http://docs.aws.amazon.com/codedeploy/latest/APIReference/),
     25 [CloudFront](http://docs.aws.amazon.com/AmazonCloudFront/latest/APIReference/),
     26 [CloudTrail](http://docs.aws.amazon.com/awscloudtrail/latest/APIReference/),
     27 [ElastiCache](http://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/),
     28 [EMR](http://docs.aws.amazon.com/ElasticMapReduce/latest/API/),
     29 [Glacier](http://docs.aws.amazon.com/amazonglacier/latest/dev/amazon-glacier-api.html),
     30 [CloudSearch](http://docs.aws.amazon.com/cloudsearch/latest/developerguide/APIReq.html),
     31 [Elastic Load Balancing](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/APIReference/),
     32 [Elastic Transcoder](http://docs.aws.amazon.com/elastictranscoder/latest/developerguide/api-reference.html),
     33 [CloudFormation](http://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/),
     34 [Elastic Beanstalk](http://docs.aws.amazon.com/elasticbeanstalk/latest/api/),
     35 [Storage Gateway](http://docs.aws.amazon.com/storagegateway/latest/userguide/AWSStorageGatewayAPI.html),
     36 [Data Pipeline](http://docs.aws.amazon.com/datapipeline/latest/APIReference/),
     37 [Direct Connect](http://docs.aws.amazon.com/directconnect/latest/APIReference/),
     38 [Redshift](http://docs.aws.amazon.com/redshift/latest/APIReference/),
     39 [OpsWorks](http://docs.aws.amazon.com/opsworks/latest/APIReference/),
     40 [SES](http://docs.aws.amazon.com/ses/latest/APIReference/),
     41 [SWF](http://docs.aws.amazon.com/amazonswf/latest/apireference/),
     42 [AutoScaling](http://docs.aws.amazon.com/AutoScaling/latest/APIReference/),
     43 [Mobile Analytics](http://docs.aws.amazon.com/mobileanalytics/latest/ug/server-reference.html),
     44 [Cognito Identity](http://docs.aws.amazon.com/cognitoidentity/latest/APIReference/),
     45 [Cognito Sync](http://docs.aws.amazon.com/cognitosync/latest/APIReference/),
     46 [Container Service](http://docs.aws.amazon.com/AmazonECS/latest/APIReference/),
     47 [AppStream](http://docs.aws.amazon.com/appstream/latest/developerguide/appstream-api-rest.html),
     48 [Key Management Service](http://docs.aws.amazon.com/kms/latest/APIReference/),
     49 [Config](http://docs.aws.amazon.com/config/latest/APIReference/),
     50 [CloudHSM](http://docs.aws.amazon.com/cloudhsm/latest/dg/api-ref.html),
     51 [Route53](http://docs.aws.amazon.com/Route53/latest/APIReference/requests-rest.html) and
     52 [Route53 Domains](http://docs.aws.amazon.com/Route53/latest/APIReference/requests-rpc.html).
     53 
     54 Indeed, the only AWS services that *don't* support v4 as of 2014-12-30 are
     55 [Import/Export](http://docs.aws.amazon.com/AWSImportExport/latest/DG/api-reference.html) and
     56 [SimpleDB](http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API.html)
     57 (they only support [AWS Signature Version 2](https://github.com/mhart/aws2)).
     58 
     59 It also provides defaults for a number of core AWS headers and
     60 request parameters, making it very easy to query AWS services, or
     61 build out a fully-featured AWS library.
     62 
     63 Example
     64 -------
     65 
     66 ```javascript
     67 var http  = require('http'),
     68     https = require('https'),
     69     aws4  = require('aws4')
     70 
     71 // given an options object you could pass to http.request
     72 var opts = {host: 'sqs.us-east-1.amazonaws.com', path: '/?Action=ListQueues'}
     73 
     74 // alternatively (as aws4 can infer the host):
     75 opts = {service: 'sqs', region: 'us-east-1', path: '/?Action=ListQueues'}
     76 
     77 // alternatively (as us-east-1 is default):
     78 opts = {service: 'sqs', path: '/?Action=ListQueues'}
     79 
     80 aws4.sign(opts) // assumes AWS credentials are available in process.env
     81 
     82 console.log(opts)
     83 /*
     84 {
     85   host: 'sqs.us-east-1.amazonaws.com',
     86   path: '/?Action=ListQueues',
     87   headers: {
     88     Host: 'sqs.us-east-1.amazonaws.com',
     89     'X-Amz-Date': '20121226T061030Z',
     90     Authorization: 'AWS4-HMAC-SHA256 Credential=ABCDEF/20121226/us-east-1/sqs/aws4_request, ...'
     91   }
     92 }
     93 */
     94 
     95 // we can now use this to query AWS using the standard node.js http API
     96 http.request(opts, function(res) { res.pipe(process.stdout) }).end()
     97 /*
     98 <?xml version="1.0"?>
     99 <ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
    100 ...
    101 */
    102 ```
    103 
    104 More options
    105 ------------
    106 
    107 ```javascript
    108 // you can also pass AWS credentials in explicitly (otherwise taken from process.env)
    109 aws4.sign(opts, {accessKeyId: '', secretAccessKey: ''})
    110 
    111 // can also add the signature to query strings
    112 aws4.sign({service: 's3', path: '/my-bucket?X-Amz-Expires=12345', signQuery: true})
    113 
    114 // create a utility function to pipe to stdout (with https this time)
    115 function request(o) { https.request(o, function(res) { res.pipe(process.stdout) }).end(o.body || '') }
    116 
    117 // aws4 can infer the HTTP method if a body is passed in
    118 // method will be POST and Content-Type: 'application/x-www-form-urlencoded; charset=utf-8'
    119 request(aws4.sign({service: 'iam', body: 'Action=ListGroups&Version=2010-05-08'}))
    120 /*
    121 <ListGroupsResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
    122 ...
    123 */
    124 
    125 // can specify any custom option or header as per usual
    126 request(aws4.sign({
    127   service: 'dynamodb',
    128   region: 'ap-southeast-2',
    129   method: 'POST',
    130   path: '/',
    131   headers: {
    132     'Content-Type': 'application/x-amz-json-1.0',
    133     'X-Amz-Target': 'DynamoDB_20120810.ListTables'
    134   },
    135   body: '{}'
    136 }))
    137 /*
    138 {"TableNames":[]}
    139 ...
    140 */
    141 
    142 // works with all other services that support Signature Version 4
    143 
    144 request(aws4.sign({service: 's3', path: '/', signQuery: true}))
    145 /*
    146 <ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    147 ...
    148 */
    149 
    150 request(aws4.sign({service: 'ec2', path: '/?Action=DescribeRegions&Version=2014-06-15'}))
    151 /*
    152 <DescribeRegionsResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
    153 ...
    154 */
    155 
    156 request(aws4.sign({service: 'sns', path: '/?Action=ListTopics&Version=2010-03-31'}))
    157 /*
    158 <ListTopicsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
    159 ...
    160 */
    161 
    162 request(aws4.sign({service: 'sts', path: '/?Action=GetSessionToken&Version=2011-06-15'}))
    163 /*
    164 <GetSessionTokenResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
    165 ...
    166 */
    167 
    168 request(aws4.sign({service: 'cloudsearch', path: '/?Action=ListDomainNames&Version=2013-01-01'}))
    169 /*
    170 <ListDomainNamesResponse xmlns="http://cloudsearch.amazonaws.com/doc/2013-01-01/">
    171 ...
    172 */
    173 
    174 request(aws4.sign({service: 'ses', path: '/?Action=ListIdentities&Version=2010-12-01'}))
    175 /*
    176 <ListIdentitiesResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
    177 ...
    178 */
    179 
    180 request(aws4.sign({service: 'autoscaling', path: '/?Action=DescribeAutoScalingInstances&Version=2011-01-01'}))
    181 /*
    182 <DescribeAutoScalingInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
    183 ...
    184 */
    185 
    186 request(aws4.sign({service: 'elasticloadbalancing', path: '/?Action=DescribeLoadBalancers&Version=2012-06-01'}))
    187 /*
    188 <DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
    189 ...
    190 */
    191 
    192 request(aws4.sign({service: 'cloudformation', path: '/?Action=ListStacks&Version=2010-05-15'}))
    193 /*
    194 <ListStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
    195 ...
    196 */
    197 
    198 request(aws4.sign({service: 'elasticbeanstalk', path: '/?Action=ListAvailableSolutionStacks&Version=2010-12-01'}))
    199 /*
    200 <ListAvailableSolutionStacksResponse xmlns="http://elasticbeanstalk.amazonaws.com/docs/2010-12-01/">
    201 ...
    202 */
    203 
    204 request(aws4.sign({service: 'rds', path: '/?Action=DescribeDBInstances&Version=2012-09-17'}))
    205 /*
    206 <DescribeDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2012-09-17/">
    207 ...
    208 */
    209 
    210 request(aws4.sign({service: 'monitoring', path: '/?Action=ListMetrics&Version=2010-08-01'}))
    211 /*
    212 <ListMetricsResponse xmlns="http://monitoring.amazonaws.com/doc/2010-08-01/">
    213 ...
    214 */
    215 
    216 request(aws4.sign({service: 'redshift', path: '/?Action=DescribeClusters&Version=2012-12-01'}))
    217 /*
    218 <DescribeClustersResponse xmlns="http://redshift.amazonaws.com/doc/2012-12-01/">
    219 ...
    220 */
    221 
    222 request(aws4.sign({service: 'cloudfront', path: '/2014-05-31/distribution'}))
    223 /*
    224 <DistributionList xmlns="http://cloudfront.amazonaws.com/doc/2014-05-31/">
    225 ...
    226 */
    227 
    228 request(aws4.sign({service: 'elasticache', path: '/?Action=DescribeCacheClusters&Version=2014-07-15'}))
    229 /*
    230 <DescribeCacheClustersResponse xmlns="http://elasticache.amazonaws.com/doc/2014-07-15/">
    231 ...
    232 */
    233 
    234 request(aws4.sign({service: 'elasticmapreduce', path: '/?Action=DescribeJobFlows&Version=2009-03-31'}))
    235 /*
    236 <DescribeJobFlowsResponse xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
    237 ...
    238 */
    239 
    240 request(aws4.sign({service: 'route53', path: '/2013-04-01/hostedzone'}))
    241 /*
    242 <ListHostedZonesResponse xmlns="https://route53.amazonaws.com/doc/2013-04-01/">
    243 ...
    244 */
    245 
    246 request(aws4.sign({service: 'appstream', path: '/applications'}))
    247 /*
    248 {"_links":{"curie":[{"href":"http://docs.aws.amazon.com/appstream/latest/...
    249 ...
    250 */
    251 
    252 request(aws4.sign({service: 'cognito-sync', path: '/identitypools'}))
    253 /*
    254 {"Count":0,"IdentityPoolUsages":[],"MaxResults":16,"NextToken":null}
    255 ...
    256 */
    257 
    258 request(aws4.sign({service: 'elastictranscoder', path: '/2012-09-25/pipelines'}))
    259 /*
    260 {"NextPageToken":null,"Pipelines":[]}
    261 ...
    262 */
    263 
    264 request(aws4.sign({service: 'lambda', path: '/2014-11-13/functions/'}))
    265 /*
    266 {"Functions":[],"NextMarker":null}
    267 ...
    268 */
    269 
    270 request(aws4.sign({service: 'ecs', path: '/?Action=ListClusters&Version=2014-11-13'}))
    271 /*
    272 <ListClustersResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
    273 ...
    274 */
    275 
    276 request(aws4.sign({service: 'glacier', path: '/-/vaults', headers: {'X-Amz-Glacier-Version': '2012-06-01'}}))
    277 /*
    278 {"Marker":null,"VaultList":[]}
    279 ...
    280 */
    281 
    282 request(aws4.sign({service: 'storagegateway', body: '{}', headers: {
    283   'Content-Type': 'application/x-amz-json-1.1',
    284   'X-Amz-Target': 'StorageGateway_20120630.ListGateways'
    285 }}))
    286 /*
    287 {"Gateways":[]}
    288 ...
    289 */
    290 
    291 request(aws4.sign({service: 'datapipeline', body: '{}', headers: {
    292   'Content-Type': 'application/x-amz-json-1.1',
    293   'X-Amz-Target': 'DataPipeline.ListPipelines'
    294 }}))
    295 /*
    296 {"hasMoreResults":false,"pipelineIdList":[]}
    297 ...
    298 */
    299 
    300 request(aws4.sign({service: 'opsworks', body: '{}', headers: {
    301   'Content-Type': 'application/x-amz-json-1.1',
    302   'X-Amz-Target': 'OpsWorks_20130218.DescribeStacks'
    303 }}))
    304 /*
    305 {"Stacks":[]}
    306 ...
    307 */
    308 
    309 request(aws4.sign({service: 'route53domains', body: '{}', headers: {
    310   'Content-Type': 'application/x-amz-json-1.1',
    311   'X-Amz-Target': 'Route53Domains_v20140515.ListDomains'
    312 }}))
    313 /*
    314 {"Domains":[]}
    315 ...
    316 */
    317 
    318 request(aws4.sign({service: 'kinesis', body: '{}', headers: {
    319   'Content-Type': 'application/x-amz-json-1.1',
    320   'X-Amz-Target': 'Kinesis_20131202.ListStreams'
    321 }}))
    322 /*
    323 {"HasMoreStreams":false,"StreamNames":[]}
    324 ...
    325 */
    326 
    327 request(aws4.sign({service: 'cloudtrail', body: '{}', headers: {
    328   'Content-Type': 'application/x-amz-json-1.1',
    329   'X-Amz-Target': 'CloudTrail_20131101.DescribeTrails'
    330 }}))
    331 /*
    332 {"trailList":[]}
    333 ...
    334 */
    335 
    336 request(aws4.sign({service: 'logs', body: '{}', headers: {
    337   'Content-Type': 'application/x-amz-json-1.1',
    338   'X-Amz-Target': 'Logs_20140328.DescribeLogGroups'
    339 }}))
    340 /*
    341 {"logGroups":[]}
    342 ...
    343 */
    344 
    345 request(aws4.sign({service: 'codedeploy', body: '{}', headers: {
    346   'Content-Type': 'application/x-amz-json-1.1',
    347   'X-Amz-Target': 'CodeDeploy_20141006.ListApplications'
    348 }}))
    349 /*
    350 {"applications":[]}
    351 ...
    352 */
    353 
    354 request(aws4.sign({service: 'directconnect', body: '{}', headers: {
    355   'Content-Type': 'application/x-amz-json-1.1',
    356   'X-Amz-Target': 'OvertureService.DescribeConnections'
    357 }}))
    358 /*
    359 {"connections":[]}
    360 ...
    361 */
    362 
    363 request(aws4.sign({service: 'kms', body: '{}', headers: {
    364   'Content-Type': 'application/x-amz-json-1.1',
    365   'X-Amz-Target': 'TrentService.ListKeys'
    366 }}))
    367 /*
    368 {"Keys":[],"Truncated":false}
    369 ...
    370 */
    371 
    372 request(aws4.sign({service: 'config', body: '{}', headers: {
    373   'Content-Type': 'application/x-amz-json-1.1',
    374   'X-Amz-Target': 'StarlingDoveService.DescribeDeliveryChannels'
    375 }}))
    376 /*
    377 {"DeliveryChannels":[]}
    378 ...
    379 */
    380 
    381 request(aws4.sign({service: 'cloudhsm', body: '{}', headers: {
    382   'Content-Type': 'application/x-amz-json-1.1',
    383   'X-Amz-Target': 'CloudHsmFrontendService.ListAvailableZones'
    384 }}))
    385 /*
    386 {"AZList":["us-east-1a","us-east-1b","us-east-1c"]}
    387 ...
    388 */
    389 
    390 request(aws4.sign({
    391   service: 'swf',
    392   body: '{"registrationStatus":"REGISTERED"}',
    393   headers: {
    394     'Content-Type': 'application/x-amz-json-1.0',
    395     'X-Amz-Target': 'SimpleWorkflowService.ListDomains'
    396   }
    397 }))
    398 /*
    399 {"domainInfos":[]}
    400 ...
    401 */
    402 
    403 request(aws4.sign({
    404   service: 'cognito-identity',
    405   body: '{"MaxResults": 1}',
    406   headers: {
    407     'Content-Type': 'application/x-amz-json-1.1',
    408     'X-Amz-Target': 'AWSCognitoIdentityService.ListIdentityPools'
    409   }
    410 }))
    411 /*
    412 {"IdentityPools":[]}
    413 ...
    414 */
    415 
    416 request(aws4.sign({
    417   service: 'mobileanalytics',
    418   path: '/2014-06-05/events',
    419   body: JSON.stringify({events:[{
    420     eventType: 'a',
    421     timestamp: new Date().toISOString(),
    422     session: {},
    423   }]}),
    424   headers: {
    425     'Content-Type': 'application/json',
    426     'X-Amz-Client-Context': JSON.stringify({
    427       client: {client_id: 'a', app_title: 'a'},
    428       custom: {},
    429       env: {platform: 'a'},
    430       services: {},
    431     }),
    432   }
    433 }))
    434 /*
    435 (HTTP 202, empty response)
    436 */
    437 
    438 // Generate CodeCommit Git access password
    439 var signer = new aws4.RequestSigner({
    440   service: 'codecommit',
    441   host: 'git-codecommit.us-east-1.amazonaws.com',
    442   method: 'GIT',
    443   path: '/v1/repos/MyAwesomeRepo',
    444 })
    445 var password = signer.getDateTime() + 'Z' + signer.signature()
    446 ```
    447 
    448 API
    449 ---
    450 
    451 ### aws4.sign(requestOptions, [credentials])
    452 
    453 This calculates and populates the `Authorization` header of
    454 `requestOptions`, and any other necessary AWS headers and/or request
    455 options. Returns `requestOptions` as a convenience for chaining.
    456 
    457 `requestOptions` is an object holding the same options that the node.js
    458 [http.request](http://nodejs.org/docs/latest/api/http.html#http_http_request_options_callback)
    459 function takes.
    460 
    461 The following properties of `requestOptions` are used in the signing or
    462 populated if they don't already exist:
    463 
    464 - `hostname` or `host` (will be determined from `service` and `region` if not given)
    465 - `method` (will use `'GET'` if not given or `'POST'` if there is a `body`)
    466 - `path` (will use `'/'` if not given)
    467 - `body` (will use `''` if not given)
    468 - `service` (will be calculated from `hostname` or `host` if not given)
    469 - `region` (will be calculated from `hostname` or `host` or use `'us-east-1'` if not given)
    470 - `headers['Host']` (will use `hostname` or `host` or be calculated if not given)
    471 - `headers['Content-Type']` (will use `'application/x-www-form-urlencoded; charset=utf-8'`
    472   if not given and there is a `body`)
    473 - `headers['Date']` (used to calculate the signature date if given, otherwise `new Date` is used)
    474 
    475 Your AWS credentials (which can be found in your
    476 [AWS console](https://portal.aws.amazon.com/gp/aws/securityCredentials))
    477 can be specified in one of two ways:
    478 
    479 - As the second argument, like this:
    480 
    481 ```javascript
    482 aws4.sign(requestOptions, {
    483   secretAccessKey: "<your-secret-access-key>",
    484   accessKeyId: "<your-access-key-id>",
    485   sessionToken: "<your-session-token>"
    486 })
    487 ```
    488 
    489 - From `process.env`, such as this:
    490 
    491 ```
    492 export AWS_SECRET_ACCESS_KEY="<your-secret-access-key>"
    493 export AWS_ACCESS_KEY_ID="<your-access-key-id>"
    494 export AWS_SESSION_TOKEN="<your-session-token>"
    495 ```
    496 
    497 (will also use `AWS_ACCESS_KEY` and `AWS_SECRET_KEY` if available)
    498 
    499 The `sessionToken` property and `AWS_SESSION_TOKEN` environment variable are optional for signing
    500 with [IAM STS temporary credentials](http://docs.aws.amazon.com/STS/latest/UsingSTS/using-temp-creds.html).
    501 
    502 Installation
    503 ------------
    504 
    505 With [npm](http://npmjs.org/) do:
    506 
    507 ```
    508 npm install aws4
    509 ```
    510 
    511 Can also be used [in the browser](./browser).
    512 
    513 Thanks
    514 ------
    515 
    516 Thanks to [@jed](https://github.com/jed) for his
    517 [dynamo-client](https://github.com/jed/dynamo-client) lib where I first
    518 committed and subsequently extracted this code.
    519 
    520 Also thanks to the
    521 [official node.js AWS SDK](https://github.com/aws/aws-sdk-js) for giving
    522 me a start on implementing the v4 signature.
    523