Secure Your Schema and Endpoint

How to control access to your schemas, endpoints and data sources

As you build out your GraphQL APIs, you may need to add some form of authentication and access control mechanisms on your schemas to prevent unauthorized use of these endpoints. You can control who can create schemas, issue queries and mutations using the following approaches:

To demonstrate these approaches, we will use the sample REST API available at https://introspection.apis.stepzen.com/customers and the following schema:

type Customer {
  email: String
  id: ID
  name: String
}
type Query {
  customerById(id: ID!): Customer
  @rest(endpoint: "https://introspection.apis.stepzen.com/customers/$id")
}

and we will be issuing curl requests in our examples.

Tip: You can also try these variations out via GraphiQL editor by toggling the Rulesets / custom headers are ON button in settings.

Use an Admin Key

Using an Admin key gives the caller full access to the schema and the queries or mutations in it, including diagnostics. An Admin key provides the caller the ability to:

  • create and update endpoints (e.g. the schema and configuration)
  • execute any GraphQL operation, regardless of access control (fieldbasedrules)
  • obtain diagnostics

An Admin key should only be used by people editing your schema, deploying and debugging GraphQL APIs. It has performance implications when used to make a GraphQL request in production.

Issue the call by including the Authorization header in a request as follows:

-H "Authorization: Apikey YOUR_ADMIN_KEY"

For a example request using an Admin key with our schema, substitute YOUR_GRAPHQL_ENDPOINT into the below.

curl YOUR_GRAPHQL_ENDPOINT --header "Authorization: Apikey $(stepzen whoami --adminkey)" --header "Content-Type: application/json" --data '{"query": "query customerSelection { customerById(id: 10) {email name}}"}' 

Tip: Note that $(stepzen whoami --adminkey) will substitute in your Admin key.

Use an API Key

To allow apps to execute operations (queries and mutations) on your endpoint(s), you can provide app developers with API keys to incorporate into their apps. The apps then call the GraphQL endpoint using an API key.

The key gives the app full access to the schema and the queries/mutations in it (but no diagnostics).

Issue the call by including the Authorization header in a request:

-H "Authorization: Apikey YOUR_API_KEY"

Similar to above, the below example, allows you to execute the Query operation with the customerById field with an API key.

curl YOUR_GRAPHQL_ENDPOINT --header "Authorization: Apikey $(stepzen whoami --apikey)" --header "Content-Type: application/json" --data '{"query": "query customerSelection { customerById(id: 10) {email name}}"}' 

Tip: Note that $(stepzen whoami --apikey) will substitute in your API key.

Tip: Use an API key, not an Admin key, to optimize runtime performance of your GraphQL requests.

Use no Keys or JWTs

API keys are a simple effective way to authenticate to your application. They are an exceptionally good match for initial development because of the simplicity of use. However, they must be protected. You cannot simply hide the API key in browser code because anyone who opens the code will see it. To safely use API keys in this way requires that they be stored in an intermediary entity that will be between the browser and your GraphQL endpoint, which isn't always desirable or practical.

StepZen supports two other forms of access:

All of these settings are made through a config.yaml file, which often holds other configuration information needed to communicate with your backends. The sections pertaining to authenticated access take the form:

fieldbasedrules:
  - rootoperationtype: Query
    publicfields:
    privatefieldspredicate:

The publicfields is a list of selection fields of an operation that can be accessed without authentication. The privatefieldspredicate is used to control the selection of fields in an operation that are not already listed in publicfields. You have access to $now, $jwt (including claims in JWT), and $operationName to set access conditions.

Unauthenticated Access with no Conditions

Operation fields can be made publicly accessible by adding them to the publicfields list of the fieldbasedrules. This makes these fields accessible without any authentication.

In our example, we can make the Query field customerById publicly executable by adding the following to the config.yaml file (or create one if it does not already exist).

fieldbasedrules:
  - rootoperationtype: Query
    publicfields:
      - customerById
    privatefieldspredicate: 

Now try running the curl command without any API keys by removing the authorization header (--header "Authorization: ApiKey...):

curl YOUR_GRAPHQL_ENDPOINT --header "Content-Type: application/json" --data '{"query": "query customerSelection { customerById(id: 10) {email name}}"}' 

To experiment, change the config.yaml to remove customerById listed in publicfields, redeploy, then rerun the above curl request. You should get an authorization error.

Note: In the future, StepZen will support public mutations, but for now, only fields of type Query can be made public (hence rootoperationtype: Query).

Authenticated Access Using a JWT

JWT based access helps restrict GraphQL operations subject to fieldbased rules. Follow the steps below to enable authenticated access using a JWT:

  1. Add the following at the top of your config.yaml:

    deployment:
      identity:
        keys:
          - algorithm: HS256
            key: my-little-secret

    Note: The string my-little-secret can be anything you choose. As long as you issue JWTs with the key that you recorded above, then the GraphQL using that JWT will be accepted as a valid call, when received by your endpoint.

    Note: HS256 is used here for demonstration only. You can, and we recommend, you use other algorithms in production.

  2. Replace the fieldbasedrules at the bottom of your config.yaml to:

    fieldbasedrules:
    - rootoperationtype: Query
      privatefieldspredicate: "?$jwt"
  3. Try this out by navigating to JWT.io and entering my-little-secret in the VERIFY SIGNATURE on the right side (and keep the PAYLOAD: DATA section as blank. For example, {}).

  4. Copy the encoded version on the left which should look similar to the following:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.QtmAB4MXp1A9X0yJXTtag0bXsmj9A4p1l9MgHF    DCOnY
  5. To verify that this works, issue a query to your endpoint with

    -H "Authorization: Bearer YOUR-JWT"

    To see this work in our running example, try the following curl command that addes the Bearer Authorization header:

    curl YOUR_GRAPHQL_ENDPOINT --header "Authorization: Bearer YOUR_JWT" --header "Content-Type: application/json" --data '{"query": "query customerSelection { customerById(id: 10) {email name}}"}' 

    You can further verify that the token works, by changing the value of the token by one character causing the call to fail.

Use JWT Claims to Further Restrict Access

The JWT in the previous section was only used to check if the caller was authenticated.

JWTs also support claims like "I am user X".

Follow the steps below to use JWT claims to further restrict access:

  1. Navigate to JWT.io and set PAYLOAD: DATA to be:

    {
      "user": "john.doe@example.com"
    }

    This generates a new JWT token like this:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obi5kb2VAZXhhbXBsZS5jb20ifQ    .QCj6sKSgw08Ob2_-XOg6JMsGugWvRHxvZs7yQ_nStes
  2. Change your config.yaml to contain the following predicate:

    privatefieldoperations: '$jwt.user: String == "john.doe@example.com"'
  3. Try out the query to verify that it works successfully. Only the JWT token with that value of user in its PAYLOAD: DATA will be allowed. You can further verify that the claim works, by changing the value of user by one character causing the call to fail.

Overall Rules

  1. An Admin key allows you full rights on a schema, including create and update.

  2. An API key has full access to all operation fields of a schema, but not ability to create and update the schema/

  3. A fieldbasedrules section in your config.yaml permits unauthenticated and JWT authenticated requests:

    • By setting publicfields, you can specify which selection fields of an operation can be accessed without authentication.
    • By setting privatefieldspredicate, you can control the selection of fields in an operation that are not listed in publicfields. You have access to $now, $jwt (including claims in JWT), and $operationName to set access conditions.
    • If you are using JWT, then you need to tell StepZen how to verify the correctness of JWT. That is accomplished through the deployment specification at the beginning of your config.yaml (as described above).

Performance Considerations

As this section has conveyed, there are two types of keys that you can use to autenticate requests to StepZen: Admin keys and API keys. These keys differ in some important ways.

An Admin key is used for creating and deploying schemas, and for running GraphQL requests in trace and debug mode. As such, a request that uses an Admin key will fetch and compile the GraphQL schema from scratch, bypassing the query cache. This is so that, as a developer, you can be certain that you are seeing information about the latest version of a deployed endpoint.

On the other hand, a request that uses an API key is optimized for performance. Consequently, no debug or trace information is gathered. Errors and exceptions are not reported other than via the HTTP Status code. Most importantly, it will leverage a query cache whenever possible to avoid re-fetching and re-compiling the GraphQL query. This means that the performance of a request that uses an API key will be significantly better than the same request that uses an Admin key.

Note: The query cache is invalidated after 60 seconds, so if you change your schema, queries that use an API key may take up to a minute to notice and respond to the new model.

This site uses cookies: By using this website, you consent to our use of cookies in accordance with our Website Terms of Use and Cookie Policy.