How to send credentials with ngx-socket-io?

4.1k Views Asked by At

I need to implement a socket.io client in Angular and I found ngx-socket-io. It seems to work fine, but I didn't find an option to send credentials when starting the connection, as described on the official page, using auth > token. (https://socket.io/docs/v4/middlewares/#Sending-credentials)

I already have the server implemented and working in this format, getting the data from socket.handshake.auth.token.

How do I send this token through ngx-socket-io?
Are there any other socket.io libraries that I can use in angular?

4

There are 4 best solutions below

3
On BEST ANSWER

I found a workaround, inserting empty options in the constructor and adding authentication right after. It's not ideal, but it seems to work normally. I'm sharing it here in case anyone else needs it.

import { AuthService } from '@my/core';
import { Socket } from 'ngx-socket-io';
import { environment } from 'src/environments/environment';

export class MySocket extends Socket {
    constructor(
        private authService: AuthService,
    ) {
        super({ url: environment.urlSocket, options: {} });
        this.ioSocket['auth'] = { token: this.authService.token };
    }
}
1
On

You can create an Injectable service that you can use to initiate the Socket connection

import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
import { Socket } from 'ngx-socket-io';
import { AuthenticationService } from '@app/auth/services/authentication.service';

@Injectable({
  providedIn: 'root'
})
export class WebSocketService {
  constructor(private socket: Socket, private authenticationService: AuthenticationService) {
    const currentUser = this.authenticationService.currentUserValue;
    this.socket.ioSocket.io.opts.query = { Authorization: `${currentUser.accessToken}` };
  }

  public sendMessage(event, message) {
    this.socket.emit(event, message);
  }

  public getMessage(eventName) {
    return new Observable(observer => {
      this.socket.on(eventName, message => {
        observer.next(message);
      });
    });
  }
}

In your component, you can inject your service:

import { WebSocketService } from './web-socket.service';

@Component({
  selector: 'app-conversation',
  templateUrl: './conversation.component.html',
  styleUrls: ['./conversation.component.scss']
})
export class MyComponent implements OnInit {
  constructor( private webSocket: WebSocketService) {}
  
  ngOnInit() {
    this.webSocket.getMessage('testing').subscribe(msg => console.log(msg));
   }
}

In your server, the token is received

handleConnection(socket: Socket) {
const token  = socket.handshake.query.Authorization;
0
On

I found a way to add auth header this way:

var token = "...";
this.socket.ioSocket.io.opts.extraHeaders = {
    "Authorization": token
}
0
On

As the validated answer didn't fit my use case because my auth credentials get in an async manner I was looking for an other solution described below:

@Injectable()
export class LiveSocket extends Socket {
    constructor(private authService: AuthService) {

        super({
            url: environment.liveServiceUrl,
            options: {
                transports: ["websocket"],
                autoConnect: false
            }
        });

        this.authService.getCurrentUserObs()
            .pipe(filter(user => !!user))
            .subscribe(user => {
                this.ioSocket.session = {
                    token: user.token,
                    // other session data here
                };
                this.connect();
            });
    }
}


@NgModule({
    exports: [ SocketIoModule ],
    providers: [ LiveSocket ]
})
export class SocketModule {}

I set the autoConnect: false inside the config to prevent the connect at first to wait for my credentials to be accessed.

Then I subscribe to my service to get the auth data asynchronously.

Whenever I get a non-null user I set the handshake element with the data and then explicitly connect() the socket.

Be warned that a new connection will be established whenever a non-null user is fired from the AuthService and I didn't unsubscribe from the Observable so this can introduce some memory leaks depending on your implementations of the Socket and AuthService.

I'm not a pro of ngx-socket-io and don't know if this solution represents an anti-pattern or not, any suggestions are welcomed!