1. Home
  2. Docs
  3. Advanced Guides
  4. Authentication

Authentication

A quick word about GraphQL Mutations vs Queries

From a technical perspective, the only differences between GraphQL Queries and Mutations is the mutation keyword, and the GraphQL spec requires mutations to by processed synchronously, where queries can be processed Async (in environments that support it).

Other than that, Queries and Mutations are the same, they’re both just strings that map to functions.

Now that we’re clear on Queries v. Mutations (both are just maps to functions), Auth is left up to the application layer, not the GraphQL API layer, although some mechanisms in GraphQL can help facilitate Auth.

Authentication & Authorization

  • Authentication: is the process of verifying who you are (logging in)
  • Authorization: is the process of verifying that you have access to something (query private data, 

Authentication with WPGraphQL

Since WPGraphQL is a WordPress plugin that adheres largely to common WordPress practices, there are many ways to make authenticated WPGraphQL requests.

For remote HTTP requests to the /graphql endpoint, existing authentication plugins should work fine. These plugins make use of sending data in the Headers of requests and validating the credentials and setting the user before execution of the API request is returned:

If the remote request is within the WordPress admin, such as the WPGraphiQL plugin, you can use the existing Auth nonce as seen in action here: https://github.com/wp-graphql/wp-graphiql/blob/master/assets/app/src/App.js#L16-L29

For non-remote requests (PHP function calls), if the context of the request is already authenticated, such as an Admin page in the WordPress dashboard, existing WordPress authentication can be used, taking advantage of the existing session. For example, if you wanted to use a GraphQL query to populate a dashboard page, you could send your query to the do_graphql_request( $query ) function, and since the request is already authenticated, GraphQL will execute with the current user set, and will resolve fields that the users has permission to resolve.

Authorization with WPGraphQL

Since WPGraphQL is built as a WordPress plugin, it makes use of WordPress core methods to determine the current user for the request, and execute with that context.

The mutations that WPGraphQL provide out of the box attempt to adhere to best practices in regards to respecting user roles and capabilities. Whether the mutation is creating, updating or deleting content, WPGraphQL checks for capabilities before executing the mutation.

For example, any mutation that would create a post will first check to make sure the current user has proper capabilities to create a post.

Mutations are not alone when it comes to checking capabilities. Some queries expose potentially sensitive data, such as the email address field in generalSettings. By default, this field will only resolve if the request is authenticated, meaning that the value of the email address is only exposed to logged in users.

A public, non authenticated request would return a null value for the field and would return an error message in the GraphQL response. However, it wouldn’t block the execution of the entire GraphQL request, just that field. So, if the request had a mix of publicly allowed fields and private fields, GraphQL would still execute the public data. For example, trying a query like:

Here, you can see that the title field was resolved, but the email field returned a null value and an error message was returned for that field explaining you don’t have permission to view the private email field.

If you try the same query in your WordPress Admin’s WPGraphiQL, you should see the email field resolve with no errors. 

Granular Control over Authorization

WPGraphQL provides many hooks and filters and allows for fine-tuning of the Schema and Resolvers for your needs.

Let’s say your system contained sensitive data in post excerpts (could be any field in your Schema) that you only wanted to expose to authenticated users. One way to handle this would be to filter the field’s resolver like so: 

apply_filters( 'graphql_Post_fields', function( $fields ) {
  // Make sure there's an excerpt field in the Schema
  if ( isset( $fields['excerpt] ) {
    // If there is no current user, that means the request is public and not authenticated
    if ( 0 === wp_get_current_user()->ID ) {
       // Override the resolve function for the excerpt field to return null
       $fields['excerpt']['resolve'] = function() {
          return null;
       }
    }
  }
} );

Note: This is just one way to approach this. There are other ways to filter and fine-tune execution within GraphQL. 

isPrivate field config

WPGraphQL also allows you to register (or filter) fields with the isPrivate config option, which will automatically ensure the request is authenticated prior to resolving. 

For example, we could accomplish the same thing as above a bit simpler:

add_filter( 'graphql_Post_fields', function( $fields ) {
  if ( isset( $fields['excerpt] ) ) {
    $fields['excerpt']['isPrivate'] => true;
  } 
  return $fields;
} );

This filter simply marks the excerpt field on the Post type as isPrivate and the core WPGraphQL plugin treats fields configured with isPrivate => true as requiring authentication and will return a null value for all non-authenticated requests. 

More granular control of roles/capabilities

Often times data is more sensitive than just

WPGraphQL also provides ways to have this kind of granular control. 

Similar to isPrivate, fields can be configured with an auth array. Within the auth array, we can configure: 

  • callback: A callback function to execute prior to resolving the field. Throwing an exception will prevent the resolver from running. Returning a value will continue execution. The callback gets passed the following context as args$field, $field_key, $source, $args, $context, $info and current $field_resolver function.
  • allowedRoles: Array of roles to check before resolving the field. If the current user does not have any of the defined roles, the field is not resolved.
  • allowedCaps: Array of caps to check before resolving the field. If the current user does not have any of the defined caps, the field is not resolved.

Examples

Below are a few examples showing how to make use of the various auth APIs baked into field configs.

isPrivate

This example adds a privateField field to the Post type that will only resolve if the request is authenticated.

register_graphql_field( 'Post', 'privateField', [
  'type' => 'String',
  'description' => __( 'Field that resolves only when request is authenticated', 'your-textdomain' ),
  'isPrivate' => true,
  'resolve' => function() {
    return 'private value';
  },
] );

auth callback

This example adds an authCallbackField to the Post type that will only resolve on Tuesdays, per the auth callback.

register_graphql_field( 'Post', 'authCallbackField', [
  'type' => 'String',
  'description' => __( 'Field that resolves only on Tuesdays', 'your-textdomain' ),
  'auth' => [
    'callback' => function() {
      if ( date( 'D' ) !== 'Tues' ) {
        throw new \Exception( __( 'Only resolves on Tuesdays', 'your-textdomain' ) );
      }
    },
  ],
  'resolve' => function() {
    return 'it is tuesday!';
  }
]);

allowedRoles

This example adds an adminField to the Post type in that will only resolve if the user making the request has the administrator role.

register_graphql_field( 'Post', 'adminField', [
  'type' => 'String',
  'description' => __( 'Field that resolves only when user is an administrator', 'your-textdomain' ),
  'auth' => [
    'allowedRoles' => [ 'administrator' ],
  ],
  'resolve' => function() {
   return 'administrator value';
  },
] );

allowedCaps

This example adds an editPostField to the Post type that will only resolve if the user making the request has the edit_posts role.

register_graphql_field( 'Post', 'editPostField', [
  'type' => 'String',
  'description' => __( 'Field that resolves only when user has the edit_posts capability', 'your-textdomain' ),
  'auth' => [
    'allowedCaps' => [ 'custom_cap' ],
  ],
  'resolve' => function() {
    return 'edit posts value';
  }
] );
Was this article helpful to you? Yes No

How can we help?