question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

I’m submitting a…


[ ] Regression 
[ ] Bug report
[ ] Feature request
[ x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

There is no information about auth in websockets microservice in the docs. Can we use middlewares / interceptors / guards / nest-passport for it ?


  1. Middlewares. As I see, it was issue #637 . In the end @adrien2p suggest to use such one:
@WebSocketGateway({
    middlewares: [AuthenticationGatewayMiddleware]
})

But as I see it’s no longer supported, isn’t it?


  1. Guards From the docs I understood that guards is like access policy. It executes before every method call and check permission to handler. But auth logic might not be here, isn’t it?

  1. Interceptors Interceptors is not called at connection time. Only on emiting, so I think it’s not our case.

  1. handleConnection() inside gateway. Is this is the place where auth might be?

Can you explain plz the best practices how to do it inside Nestjs ecosystem? 😉

Thanks.

Environment


[System Information]
OS Version     : Linux 4.15
NodeJS Version : v8.9.1
NPM Version    : 6.1.0
[Nest Information]
websockets version : 5.4.0
common version     : 5.4.0
core version       : 5.4.0
cqrs version       : 5.1.1

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:12 (2 by maintainers)

github_iconTop GitHub Comments

6reactions
TristanMarioncommented, Jan 10, 2019

This is how I achieved it :

Guard :

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
/*
    Custom imports for AuthService, jwt secret, etc...
*/
import * as jwt from 'jsonwebtoken';

@Injectable()
export class WsJwtGuard implements CanActivate {
    constructor(private authService: AuthService) {}

    async canActivate(context: ExecutionContext) {
        const client = context.switchToWs().getClient();
        const cookies: string[] = client.handshake.headers.cookie.split('; ');
        const authToken = cookies.find(cookie => cookie.startsWith('jwt')).split('=')[1];
        const jwtPayload: JwtPayload = <JwtPayload> jwt.verify(authToken, yourSecret);
        const user: User = await this.authService.validateUser(jwtPayload);
        // Bonus if you need to access your user after the guard 
        context.switchToWs().getData().user = user;
        return Boolean(user);
    }
}

Gateway :

@UseGuards(WsJwtGuard)
@SubscribeMessage('events')
onEvent(client, data) {
    // data.user contains your user if you set it in the guard
}
1reaction
jsdevtomcommented, Dec 29, 2018

Here is an example implementation:

import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { bindNodeCallback, Observable, of } from 'rxjs';
import { JwtPayload } from './jwt-payload.interface';
import * as jwt from 'jsonwebtoken';
import { catchError, flatMap, map } from 'rxjs/operators';
import { User } from '../user/user.entity';
import { AuthService } from './auth.service';

@Injectable()
export class JwtWsGuard implements CanActivate {
  constructor(
    protected readonly authService: AuthService,
  ) {
  }

  canActivate(
    context: ExecutionContext,
  ): Observable<boolean> {
    const data = context.switchToWs().getData();
    const authHeader = data.headers.authorization;
    const authToken = authHeader.substring(7, authHeader.length);
    const verify: (...args: any[]) => Observable<JwtPayload> = bindNodeCallback(jwt.verify) as any;

    return verify(authToken, process.env.JWT_SECRET_KEY, null)
      .pipe(
        flatMap(jwtPayload => this.authService.validateUser(jwtPayload)),
        catchError(e => {
          console.error(e);
          return of(null);
        }),
        map((user: User | null) => {
          const isVerified = Boolean(user);

          if (!isVerified) {
            throw new UnauthorizedException();
          }

          return isVerified;
        }),
      );
  }
}

Where on the client you would authenticate by passing ‘dummy’ headers in the data object like so:

    const websocket = this.websocketService
      .createConnection(`ws://localhost:8080`);
    const jsonWebToken = getJwtSomehow();

    websocket.subscribe(
      (msg) => console.log('message received: ',  msg),
      (err) => console.log(err),
      () => console.log('complete')
    );

    websocket.next({
      event: 'YOUR_EVENT_NAME',
      data: {
        // ...
        headers: {
          authorization: `Bearer ${jsonWebToken}`
        }
      },
    });
Read more comments on GitHub >

github_iconTop Results From Across the Web

Authentication - websockets 10.4 documentation
Authentication #. The WebSocket protocol was designed for creating web applications that need bidirectional communication between clients running in browsers ...
Read more >
WebSocket Token-Based Authentication - Nuvalence
Requests to authenticate are made to the HTTP endpoint /authenticate/token with the internal authentication token securely passed in the header of the request....
Read more >
Websocket Security - authentication - Stack Overflow
To secure your messages, use WebSockets over SSL/TLS (wss:// instead of ws://). Don't roll your own crypto. Concerning authentication.
Read more >
Authenticating Users Over WebSockets with JSON Web ...
In this guide, you will learn how to use Websockets and JSON Web Tokens, which are also ... By default, WebSockets lack authentication, ......
Read more >
Authenticating Websockets - DEV Community ‍ ‍
Generally speaking the Explicit Authentication Message strategy is a good choice for how to establish authentication on WebSocket connections.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found