, (*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##