 
 
 , (*1)
, (*1)
License
GPL v3 or later, (*2)
GraphQL JSON Web Token authenticator
This module provides a JWT-interface for creating JSON Web Tokens for authentication., (*3)
Installation
composer require firesphere/graphql-jwt
The default config is available in _config\config.yml., (*4)
In order to securely process and store data via JWT,
you need to set a secret key in your .env file:, (*5)
JWT_SIGNER_KEY="[your secret key]"
A quick way to generate a secure random value value for JWT_SIGNER_KEY is through a PHP CLI command:, (*6)
php -r 'echo substr(base64_encode(random_bytes(64)), 0, 64) . "\n";'
You can also use public/private key files., (*7)
JWT_SIGNER_KEY="./path/to/private.key"
JWT_PUBLIC_KEY="./path/to/public.key"
Note: Relative paths will be relative to your BASE_PATH (prefixed with ./), (*8)
Currently, only RSA keys are supported. ECDSA is not supported. The keys in the test-folder are generated by an online RSA key generator., (*9)
The signer key for HMAC can be of any length (keys longer than B bytes are first hashed using H). However, less than L bytes is strongly discouraged as it would decrease the security strength of the function.. Thus, for SHA-256 the signer key should be between 16 and 64 bytes in length., (*10)
The keys in tests/keys should not be trusted!, (*11)
Configuration
Since admin/graphql is reserved exclusively for CMS graphql access, it will be necessary for you to register a custom schema for
your front-end application, and apply the provided queries and mutations to that., (*12)
For example, given you've decided to create a schema named frontend at the url /api, (*13)
---
Name: my-graphql-schema
---
SilverStripe\GraphQL\Manager:
  schemas:
    frontend:
      types:
        MemberToken: 'Firesphere\GraphQLJWT\Types\MemberTokenTypeCreator'
        Member: 'Firesphere\GraphQLJWT\Types\MemberTypeCreator'
      mutations:
        createToken: 'Firesphere\GraphQLJWT\Mutations\CreateTokenMutationCreator'
        refreshToken: 'Firesphere\GraphQLJWT\Mutations\RefreshTokenMutationCreator'
      queries:
        validateToken: 'Firesphere\GraphQLJWT\Queries\ValidateTokenQueryCreator'
---
Name: my-graphql-injections
---
SilverStripe\Core\Injector\Injector:
  SilverStripe\GraphQL\Manager.frontend:
    class: SilverStripe\GraphQL\Manager
    constructor:
      identifier: frontend
  SilverStripe\GraphQL\Controller.frontend:
    class: SilverStripe\GraphQL\Controller
    constructor:
      manager: '%$SilverStripe\GraphQL\Manager.frontend'
---
Name: my-graphql-routes
---
SilverStripe\Control\Director:
  rules:
    api:
      Controller: '%$SilverStripe\GraphQL\Controller.frontend'
      Stage: Live
Log in
To generate a JWT token, send a login request to the createToken mutator:, (*14)
mutation {
  createToken(Email: "admin", Password: "password") {
    Token, // ...request or you won't have a token
    ID,
    FirstName,
    Surname
  }
}
Validate token
If you have an app and want to validate your token, you can address the validateToken method:, (*15)
query validateToken {
  validateToken {
    Valid
    Message
    Code
  }
}
It only needs to call the endpoint. The token should be in the header, via your middleware for the request, as a Authorization: Bearer [token]. If the token is valid, you'll get a response like this:, (*16)
{
  "data": {
    "validateToken": {
      "Valid": true,
      "Message": "",
      "Code": 200,
      "__typename": "ValidateToken"
    }
  }
}
If the token is invalid, Valid will be false., (*17)
Anonymous tokens
Although not advised, it's possible to use anonymous tokens. When using an anonymous authenticator, SilverStripe
will generate a default database record in the Members table with the Email anonymous and no permissions by default., (*18)
To enable anonymous tokens, add the following to your configuration .yml:, (*19)
SilverStripe\Core\Injector\Injector:
  Firesphere\GraphQLJWT\Mutations\CreateTokenMutationCreator:
    properties:
      CustomAuthenticators:
        - Firesphere\GraphQLJWT\Authentication\AnonymousUserAuthenticator
You can then create an anonymous login with the below query., (*20)
mutation {
  createToken(Email: "anonymous") {
    Token
  }
}
Note: If the default anonymous authenticator doesn't suit your purposes, you can inject any other
core SilverStripe authenticator into CustomAuthenticators., (*21)
Warning: The default AnonymousUserAuthenticator is not appropriate for general usage, so don't
register this under the core Security class!, (*22)
Enable CORS
To use JWT, CORS needs to be enabled. This can be done by adding the following to your configuration .yml:, (*23)
SilverStripe\GraphQL\Controller:
  cors:
    Enabled: true
    Allow-Origin: "*"
    Allow-Headers: "Authorization, Content-Type"
    Allow-Methods: "GET, POST, OPTIONS"
    Max-Age: 86400 # ...in seconds
Usage
After logging in, you will receive a token which can be used for further requests. This token should be in the header of the request with the Bearer as signature:, (*24)
Authorization: Bearer [token]
Prefix
A prefix can be optionally associated with the unique identifier of a JWT record.
This can make it easier to distinguish JWT records created in different contexts,
e.g. on a specific domain or environment type. It is not required for security purposes., (*25)
JWT_PREFIX="[your secret prefix]"
Security
Currently, the default method for encrypting the JWT is with SHA256. JWT is signed with multiple factors; including the host, audience (app/remote user), a secret key and a timeframe within which the token is valid. Only one device can be logged in at the time., (*26)
Supported services
By default, JWT only supports login. As it's tokens can not be disabled, nor used for password changes or resets., (*27)
Caveats
When using php under CGI/FastCGI mode with Apache, the Authorization header might not work correctly, see issue#15. The workaround is simple, just add SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0 in your .htaccess file (refer)., (*28)
Examples
A Postman collection can be found in the extra folder., (*29)
Cow?
Of course!, (*30)
               /( ,,,,, )\
              _\,;;;;;;;,/_
           .-"; ;;;;;;;;; ;"-.
           '.__/`_ / \ _`\__.'
              | (')| |(') |
              | .--' '--. |
              |/ o     o \|
              |           |
             / \ _..=.._ / \
            /:. '._____.'   \
           ;::'    / \      .;
           |     _|_ _|_   ::|
         .-|     '==o=='    '|-.
        /  |  . /       \    |  \
        |  | ::|         |   | .|
        |  (  ')         (.  )::|
        |: |   |;  U U  ;|:: | `|
        |' |   | \ U U / |'  |  |
        ##V|   |_/`"""`\_|   |V##
           ##V##         ##V##