We created a web-socket server using the ws package. The server runs in AWS EC2 instances. We wanted to authenticate the incoming web-socket requests. In-case of HTTP requests, the header will have the "Authorization" key which will be used but in-case of web-socket requests, it was not possible to send the "Authorization" header because web-socket request doesn't support custom headers .
We were left with three choices
- Placing the web-socket-server behind an API Gateway
- Placing the web-socket-server behind an ALB
- Authentication inside the web-socket server
1. Placing the web-socket-server behind an API Gateway
The "Web-socket API Gateway" in AWS supports back-end which is a HTTP-server/lambda and not a web-socket-server Reference
2.Placing the web-socket-server behind an ALB
Authentication using ALB and Cognito. When a request is sent to the web-socket-server, the ALB checks for the "AWSELBAuthSessionCookie" cookie. If the cookie is present then it forwards the request to the web-socket-server else it redirects the user to the "Hosted-UI" ("Hosted-UI" is a default sign in page provided by AWS Cognito). The Hosted-UI allows some level of customization(like adding logo) but not complete design changes.
So to redirect to a custom sign-in page(completely developed in house), the sign-in functionality should be written. We used Amplify to handle the sign-in process.
If ALB has to be integrated with Cognito, "client-secret" should be enabled in Cognito. But if "client secret" is enabled, it was not possible to sign-in using Amplify since client secrets should not be sent from the browsers (should to be sent from trusted sources ie. back-end). Reference
It sounds like the AWS Javascript SDK will never support the use of a Cognito App Client with Client Secret, thus never being used with the ALB.
To solve the client secret issue in the browser, we created a lambda function behind an API Gateway which will be called when the user clicks the Sign-in button. The username and password is hashed and sent as payload. The lambda function has the client secret and along with the username and password makes a Cognito call . The authentication was successful and an access-token was received as a response but using the access-token it was not possible to generate the "AWSELBAuthSessionCookie" cookie Reference.
you're getting JWT tokens from cognito, and you want to use them to authenticate a web request through ALB that is using cognito authentication checks. Which is to say you're trying to find some way to generate the AWSELBAuthSessionCookie cookies yourself, or craft a call to /oauth2/idpresponse so that the ALB sets these cookies. Short answer: You can't as of June 2021.
Conclusion:
If authentication is done using ALB then the default sign-in page provided by Cognito can only be used. Using a custom sign-in page is not possible.
3. Authentication inside the web-socket server
After the browser connects with the web-socket server, the browser sends a JWT token. The web-socket server check the token. If the token is invalid the connection will be terminated else the connection will continue. This is know as a ticket-based-authentication system.
My doubts:
- I feel that the chances of DoS and DDoS attacks in a ticket-based-authentication system is high. Is it right?
- Is there a better way of authentication for websockets?
We proceeded by placing the Web socket server behind an ALB. But we automated the sign-in process using a separate micro-service (lets call the micro-service as wss-auth)
Application setup:
We created two app clients in Cognito.
The user is provided with a custom sign in page. Amplify is used for the sign in process and it uses the "App Client 1" from the Cognito for the authentication process.
The following steps are used for authentication:
Browser(app.companyDomain.com) sends a request to the wss-auth service
wss-auth service(api.companyDomain.com) processes the request and sets the cookie
Browser makes a request to the web-socket server(wss.companyDomain.com)
Pros and Cons
Cons:
Pros: When compared to the ticket based authentication system, I feel this is way more secure.
NOTE:
Sometimes in chrome cookie sent is not being shown. Check in Firefox