Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/firesphere/silverstripe-graphql-jwt

JWT Authentication for GraphQL
https://github.com/firesphere/silverstripe-graphql-jwt

anonymous-tokens authentication authentication-middleware cors graphql hacktoberfest headless jwt rsa-key security signer-key

Last synced: 2 months ago
JSON representation

JWT Authentication for GraphQL

Awesome Lists containing this project

README

        

[![CircleCI](https://circleci.com/gh/Firesphere/silverstripe-graphql-jwt/tree/master.svg?style=svg)](https://circleci.com/gh/Firesphere/silverstripe-graphql-jwt/tree/master)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/Firesphere/silverstripe-graphql-jwt/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/Firesphere/silverstripe-graphql-jwt/?branch=master)
[![codecov](https://codecov.io/gh/Firesphere/silverstripe-graphql-jwt/branch/master/graph/badge.svg)](https://codecov.io/gh/Firesphere/silverstripe-graphql-jwt)

# License

[GPL v3 or later](LICENSE.md)

# GraphQL JSON Web Token authenticator

This module provides a JWT-interface for creating JSON Web Tokens for authentication.

## Installation

```
composer require firesphere/graphql-jwt
```

The default config is available in `_config\config.yml`.

In order to securely process and store data via JWT,
you need to set a secret key in your `.env` file:

```ini
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:

```
php -r 'echo substr(base64_encode(random_bytes(64)), 0, 64) . "\n";'
```

You can also use public/private key files.

```ini
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 `./`)

Currently, only RSA keys are supported. ECDSA is not supported. The keys in the test-folder are generated by an online RSA key generator.

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.](https://tools.ietf.org/html/rfc2104#section-3). Thus, for SHA-256 the signer key should be between 16 and 64 bytes in length.

**The keys in `tests/keys` should not be trusted!**

## 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.

For example, given you've decided to create a schema named `frontend` at the url `/api`

```yml
---
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:

```graphql
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:

```graphql
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:

```json
{
"data": {
"validateToken": {
"Valid": true,
"Message": "",
"Code": 200,
"__typename": "ValidateToken"
}
}
}
```

If the token is invalid, `Valid` will be `false`.

## 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.

To enable anonymous tokens, add the following to your configuration `.yml`:

```yaml
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.

```graphql
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`.

Warning: The default `AnonymousUserAuthenticator` is not appropriate for general usage, so don't
register this under the core `Security` class!

## Enable CORS

To use JWT, CORS needs to be enabled. This can be done by adding the following to your configuration `.yml`:

```yaml
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:

```
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.

```
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.

## Supported services

By default, JWT only supports login. As it's tokens can not be disabled, nor used for password changes or resets.

## Caveats

When using php under CGI/FastCGI mode with Apache, the `Authorization` header might not work correctly, see [issue#15](https://github.com/Firesphere/silverstripe-graphql-jwt/issues/15). The workaround is simple, just add `SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0` in your `.htaccess` file ([refer](http://php.net/manual/en/features.http-auth.php#114877)).

## Examples

A Postman collection can be found in the `extra` folder.

# Cow?

Of course!

```
/( ,,,,, )\
_\,;;;;;;;,/_
.-"; ;;;;;;;;; ;"-.
'.__/`_ / \ _`\__.'
| (')| |(') |
| .--' '--. |
|/ o o \|
| |
/ \ _..=.._ / \
/:. '._____.' \
;::' / \ .;
| _|_ _|_ ::|
.-| '==o==' '|-.
/ | . / \ | \
| | ::| | | .|
| ( ') (. )::|
|: | |; U U ;|:: | `|
|' | | \ U U / |' | |
##V| |_/`"""`\_| |V##
##V## ##V##
```