Client Onboarding

Client Onboarding

Getting started

Here are the first steps for FireFly client onboarding:

  1. Make sure you have an x-api-key:

  2. Complete the authentication.

  3. Set the headers.

  4. Now you’re ready to write queries - see our GraphQL web portal where you can try queries and access documentation for the schema.

When to Use Which Process

For client onboarding and API key requests: Use the trouble ticket template

For FireFly feature development: Use the JIRA intake template

Authentication

Choose the correct authentication method

  • If you have an ATNA token, which are available to internal Amazon employees, you’re all set to proceed.

  • If you have an ATZA token, which are available to developers external to Amazon and issued by the Login With Amazon team, utilize this.

  • If you are internal to Amazon without an ATNA token, you’ll need special approval to get Amazon Identity and Access Management or “IAM” access to our service. Mention this in your trouble ticket.

  • If you only need to access specific data you may be able to call FireFly anonymously if you provide certain details. See Anonymous Auth.

Authentication steps

First Party Auth: ATNA

Tip: If you just wish to test a sample ATNA query, you can use this script to generate the Auth header one time. This script is not intended for production.

npx ts-node amu_webapi/tst/utils/GenerateProfileAwareATNAToken.ts

Copy-paste the resulting string into your “Authorization” header, and prepend with “AmznMusic”. For example, "Authorization": "AmznMusic GENERATED_TOKEN"

  1. Source the Atna token from existing integrations such as MAP.

  2. Create a JSON payload with the signature: { "access_token", "deviceId", "deviceType" }

    Example authentication structure:

    {
      "access_token": "Atna|EwICIBKjpPxJ3G...", # Atna Token
      "deviceId": "AB904373C9B947F5...", # DeviceId for resolving Atna Token
      "deviceType":"A2825..." # DeviceType for resolving Atna Token
    }
    

    If you’re developing on your own you can create a .json file in your terminal.

  3. Utilize Base64 to encode theJSON payload.
    a. If you’re developing locally:

    1. You should already have base64 installed in your terminal.

    2. Create a .json file containing the authentication payload from the example authentication structure above.

    3. Encode it with the command cat test.json | base64

    4. Use the resulting string as part of the authorization header in subsequent steps. It should look like the following: ewogICJhY2Nlc3NfdG9rZW4iOiAi...

    b. The following is an example of conversion to Base64 in the code:

    console.log(Buffer.from(
            JSON.stringify({
                access_token: 'Atna|EwI...',
                deviceId: 'AB904373C9B947F5...',
                deviceType: 'A2825...',
            })
          )
        );
    
  4. Provide the encoded string as Authorization header. Use a prefix with the unique code AmznMusic.

    Example of Base 64: ewogICJhY2Nlc3NfdG9rZW4iOiAi... Header Signature:

    Headers: {
      "x-api-key" : "amzn1.application.XXX"
      "Authorization": "AmznMusic ewogICJhY2Nlc3NfdG9rZW4iOiAi..."
    }
    

Third Party Auth: Atza

Example header signature:

Headers: {
  "x-api-key" : "amzn1.application.XXX"
  "Authorization": "Bearer Atza|IwEBIPz97iea3XQY_H...",
  'referral': 'linkfire', // Optional
}

First Party Auth: IAM

IAM authentication for Firefly can be accessed specifically from the /dev/internal or /prod/internal endpoint.

For example,[https://XXXXXX.execute-api.us-east-1.amazonaws.com/dev/internal](https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/internal). IAM currently only supports POST GraphQL requests.

Enable your client to call FireFly with IAM

  1. A security profile x-api-key for your client will be needed if one does not already exist.

  2. Within the FireFly CDK repo, ceate IAM dev and prod roles for your feature in the iamRole field of your partner application. See the example here, using the createServiceIamRole function:

const yourClientName = this.createPartnerApplication({
  restId,
  partnerName: 'AmazonMusic.XXX.XXX',
  applicationId: 'amzn1.application.XXX',
  rateLimit: 25,
  iamRole: this.createServiceIamRole(`your-client-name-${stage}`, stage, region, awsAccountIds[]).roleName,
});
  • For the iamRole field, set the name to include -${stage} at the end. The last parameter of createServiceIamRole, awsAccountIds, is an optional array of AWS account ids you should add to the trust policy of this new role so that it can be assumed for FireFly calls.

  • Your dev role will have permission to hit the NA, EU, and FE dev endpoints, while your prod role will have permission to hit the NA, EU, and FE prod endpoints.

Calling FireFly with IAM auth after setting up your service’s IAM access

  1. Use the following required headers:

    • x-api-key (security profile ID)

    • customer-id

    • device-id,

    • device-type

    • market or music-territory

    const headers = {
        'customer-id': 'yourCustomerId',
        'device-id': 'yourDeviceId',
        'device-type': 'yourDeviceType',
        market: 'US',
        'x-api-key': 'amzn1.application.XXX',
        'profile-id': 'amzn1.actor.person.oid.AF9MXXXX', // Optional
    };
    
  2. Use the STS service to assume a role and get your keys as documented in this Knowledge Center article. You will then have an AWS access key and secret key.

    If you’re using Insomnia, configure the AWS IAM authentication with your access key and secret key.

  3. Add your GraphQL query to the request, and send using the auth and headers from the previous step.

Anonymous Auth

To gain access to anonymous auth for your client or service:

  1. A new security profile specifically for anonymous auth for your client is required — even if an x-api-key already exists for your client for non-anonymous use cases.

    • This can be obtained as the MusicFirefly user utilizing the Firefly security profile management documentation.

    • Or, reach out to the Devex API team on-call if you cannot access the MusicFirefly user and/or don’t have a security profile setup for your client.

  2. Create a JSON header object containing these required headers:

    • x-api-key (security profile ID)

    • device-id

    • device-type

    • market or music-territory

    • x-amzn-session-id

    Note: Your request headers should not contain an Authorization header. The absence of an Authorization header is how we identify if a request should be validated using Anonymous auth.

    Headers: {
      'x-api-key' : 'amzn1.application.XXX'
      'device-id': 'yourDeviceId',
      'device-type': 'yourDeviceType',
      'market': 'US',
      'x-amzn-session-id': '000-0000000-0000000',
    }
    
  3. Construct a HTTP request to FireFly with your preferred client with the above headers (and no Authorization header).

Optional headers

Features and modifiable behavior

The FireFly API allows clients to provide a series of flags under the x-amzn-feature-flags in a comma delimited format to modify resolver or other behavior on the stack.

Currently the API supports the following optional properties for the feature-flag header:

Value

Description

Warnings

trace

The extensions response will be hydrated with trace metadata indicating how long a query took to resolve alongside where things delayed.

complexity

The extensions response will be hydrated with complexity metadata indicating the score of the query submitted against the budget for any query.

Cache Control

The FireFly API allows clients to control how clients interface with the various caching strategies at play. Currently the API supports the following optional headers for granular control. They can also be combined within a single header as follows:

"cache-control": "no-cache, no-store"

Header

Value

Description

Warnings

cache-control

no-cache

Resolutions will skip retrieval from cache-fleets and resolve directly from providers.

This behavior will result in higher TPS on upstream services and can contribute to higher latencies. It’s recommended to only provide this header in non-productionized environments or as a workaround until upstream providers can provide mechanisms for event updates.

cache-control

no-store

Resolutions from upstream services will not result in persisting state in cache-fleets

This header will result in other callers not benefiting from previous resolutions. It’s recommended to only provide this header in non-productionized environments or as a workaround until upstream providers can provide mechanisms for event updates.

MusicTerritory Retargeting

Some clients may have a use-case where they do not require customer context but wish to retrieve data from non-contextualized stores, such as music or podcast catalogs, or via search. This API provides clients with the ability to ‘retarget’ a user’s account associated MusicTerritory to view collections in other regions.

Note: Only read operations will work, and results may vary depending on your use case or which upstream API service you call.

Header

Value

Description

market

<Any 2 Letter MusicTerritory Code>

For supported values look at MusicTerritoryUtils

GraphQL Query best practices

See the Insomnia guide to set up this client to test your queries.

API Constraints and Resource Limits

The Firefly API has implemented a few safeguards to protect upstream services and encourage healthier query structures from clients.

Request Payload Constraints

A constraint has been added to the Query string received by this API. Any request query with a character limit of 4096 or more will be invalidated and the service will return a 413 Large Payload error. If you are encountering this error, it indicates you may be attempting to achieve too much in a single call and should break up the request into multiple calls. Other implications of a large payload like this would be higher latency and stress on upstream providers.

Node Resource Limit (Query Entity Hydration Limit)

This constraint enforces the API to not hydrate more than 300 entities of a specific type within a single query. This constraint is placed to encourage users streamlining queries and only requesting nodes necessary for a single call.

For example, with this limit, if a user requests 100 playlists, with 50 tracks, it would equate to:

  • 100 Playlist Entity requests

  • 100*50 = 5000 Track Entity requests

The constraint will result in:

  • 100 Playlists retrieved (with a remainder of 200 for this query)

  • 300 Tracks retrieved

  • 4700 Tracks blocked due to the resource limit constraint