github.com/anycable/anycable-go@v1.5.1/docs/jwt_identification.md (about)

     1  # JWT authentication
     2  
     3  AnyCable provides support for [JWT][jwt]-based authentication and identification.
     4  
     5  We use the term "identification", because you can also pass a properly structured information as a part of the token to not only authentication the connection but also set up _identifiers_ (in terms of Action Cable). This approach brings the following benefits:
     6  
     7  - **Performance**. No RPC call is required during the connection initiation, since we already have identification information. Thus, less load on the RPC server, much faster connection time (at least, 2x faster).
     8  - **Usability**. Universal way of dealing with credentials (no need to deal with cookies for web and whatever else for mobile apps).
     9  - **Security**. CSRF-safe by design. Configurable life time for tokens makes it easier to keep access under control.
    10  
    11  ## Usage
    12  
    13  > See the [demo](https://github.com/anycable/anycable_rails_demo/pull/23) of using JWT identification in a Rails app with [AnyCable JS client library][anycable-client].
    14  
    15  **NOTE**: Currently, we only support the HMAC signing algorithms.
    16  
    17  By default, the `--secret` configuration parameter is used as a JWT secret key. If you want to use a custom key for JWT, you can specify it via the `--jwt_secret` (`ANYCABLE_JWT_SECRET`) parameter.
    18  
    19  Other configuration options are:
    20  
    21  - (_Optional_) **--jwt_param** (`ANYCABLE_ID_PARAM`, default: "jid"): the name of a query string param or an HTTP header, which carries a token. The header name is prefixed with `X-`.
    22  - (_Optional_) **--enforce_jwt** (`ANYCABLE_ENFORCE_JWT`, default: false): whether to require all connection requests to contain a token. Connections without a token would be rejected right away. If not set, the servers fallbacks to the RPC call (if RPC is configured) or would be accepted if authentication is disabled (`--noauth`).
    23  
    24  A client must provide an identification token either via a query param or via an HTTP header (if possible). For example:
    25  
    26  ```js
    27  import { createCable } from '@anycable/web'
    28  
    29  let cable = createCable('ws://cable.example.com/cable?jid=[JWT_TOKEN]')
    30  ```
    31  
    32  The token MUST include the `ext` claim with the JSON-encoded connection identifiers.
    33  
    34  ## Generating tokens
    35  
    36  ### Rails/Ruby
    37  
    38  When using AnyCable Ruby/Rails SDK, you can generate tokens as follows:
    39  
    40  ```ruby
    41  token = AnyCable::JWT.encode({user: current_user})
    42  
    43  # Setting TTL is also possible
    44  token = AnyCable::JWT.encode({user: current_user}, expires_at: 10.minutes.from_now)
    45  ```
    46  
    47  If you don't want to use our SDKs (why?), here is how you can generate tokens yourself:
    48  
    49  ```ruby
    50  require "jwt"
    51  require "json"
    52  
    53  ENCRYPTION_KEY = "some-sercret-key"
    54  
    55  # !!! Expiration is the responsibility of the token issuer
    56  exp = Time.now.to_i + 30
    57  
    58  # Provides the serialized values for identifiers (`identified_by` in Action Cable)
    59  identifiers = {user_id: 42}
    60  
    61  # JWT payload
    62  payload = {ext: identifiers.to_json, exp: exp}
    63  
    64  puts JWT.encode payload, ENCRYPTION_KEY, "HS256"
    65  ```
    66  
    67  ## JavaScript/TypeScript
    68  
    69  You can use [AnyCable server-side JS SDK](https://github.com/anycable/anycable-serverless-js) to generate tokens as follows:
    70  
    71  ```js
    72  import { identificator } from "@anycable/serverless-js";
    73  
    74  const jwtSecret = "very-secret";
    75  const jwtTTL = "1h";
    76  
    77  export const identifier = identificator(jwtSecret, jwtTTL);
    78  
    79  // Then, somewhere in your code, generate a token and provide it to the client
    80  const userId = authenticatedUser.id;
    81  const token = await identifier.generateToken({ userId });
    82  ```
    83  
    84  ## PHP
    85  
    86  You can use the following snippet to generate tokens in PHP:
    87  
    88  ```php
    89  use Firebase\JWT\JWT;
    90  
    91  $identifiers = ['user_id' => 42];
    92  $payload = ['ext' => json_encode($identifiers), 'exp' => time() + 300];
    93  $jwt = JWT::encode($payload, $ENCRYPTION_KEY, 'HS256');
    94  ```
    95  
    96  ## Python
    97  
    98  Here is an example Python code to generate AnyCable tokens:
    99  
   100  ```python
   101  import json
   102  import jwt
   103  import time
   104  
   105  identifiers = {'user_id': 42}
   106  payload = {'ext': json.dumps(identifiers), 'exp': int(time.time()) + 300}
   107  jwt.encode(payload, ENCRYPTION_KEY, algorithm='HS256')
   108  ```
   109  
   110  ### Handling expired tokens
   111  
   112  > 🎥 Check out this [AnyCasts episode](https://anycable.io/blog/anycasts-using-anycable-client/) to learn more about the expiration problem and how to solve it using [anycable-client](https://github.com/anycable/anycable-client).
   113  
   114  Whenever a server encounters a token that has expired, it rejects the connection and send the `disconnect` message with `reason: "token_expired"`. It's a client responsibility to handle this situation and refresh the token.
   115  
   116  See, for example, how [anycable-client handles this](https://github.com/anycable/anycable-client#refreshing-authentication-tokens).
   117  
   118  [jwt]: https://jwt.io
   119  [anycable-client]: https://github.com/anycable/anycable-client