Authentication with token but no Authorization header
See original GitHub issueWe use react-native so this issue happens in JavaScript, but on a mobile device (either Android or iOS), not in a browser.
When I open a new websocket connection in a browser tab where I am logged in to our website, the browser adds a bunch of headers to the request, including cookie with my auto login token. In this case @channel_session_user_from_http
picks up on my user and authenticates.
We use django-rest-framework with rest_framework.authentication.TokenAuthentication
in the app.
When I try and open a websocket from my react-native app there is no session. As far as I have been able to find out I also have no way of manually setting headers on the ‘upgrade’ request that initiates the websocket connection after instantiating with new Websocket()
. For each XMLHttpRequest
I set an ‘Authorization’ header as follows:
request.setRequestHeader('Authorization',
Token ${authToken})
I found in the docs we are able to use the querystring session_key=
like so:
socket = new WebSocket("ws://127.0.0.1:9000/?session_key=abcdefg");
But I only have the auth token in our app, and that did not seem to work here, while the token did get eaten before ws_connect
gets called from websocket.connect
.
I’m running Daphne with one worker to test this, but I did set up nginx to pass everything to Daphne. Everything I do in the browser seems to work, like all normal http and using websockets, because the browser handles auth once I am logged in.
The error I get in the worker is:
AttributeError: 'AnonymousUser' object has no attribute 'get_events_with_edit_permissions'
so the actual error is Django has no way of finding out which user I am from the connect request.
I get the following message['headers']
: (this was without using session_key
)
[ [b'upgrade', b'websocket'],
[b'x-forwarded-for', b'46.129.153.456'],
[b'user-agent', b'okhttp/3.4.1'],
[b'x-real-ip', b'46.129.153.456'],
[b'origin', b'https://www.chipta.com/'],
[b'host', b'www.chipta.com'],
[b'sec-websocket-version', b'13'],
[b'sec-websocket-key', b'8XSr4kJslkaVBam74sYKXOg=='],
[b'connection', b'upgrade'],
[b'x-forwarded-proto', b'https'],
[b'accept-encoding', b'gzip']
]
When I connect from the browser I get a lot more: (and my user is known, so channel_session_user_from_http
works)
[ [b'upgrade', b'websocket'],
[b'x-forwarded-for', b'46.129.153.456'],
[ b'accept',
b'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'],
[b'accept-encoding', b'gzip, deflate, br'],
[ b'user-agent',
b'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0'],
[b'sec-websocket-version', b'13'],
[b'connection', b'upgrade'],
[b'sec-websocket-extensions', b'permessage-deflate'],
[b'accept-language', b'en-US,en;q=0.5'],
[b'x-real-ip', b'46.129.153.456'],
[b'pragma', b'no-cache'],
[b'origin', b'https://www.chipta.com'],
[b'host', b'www.chipta.com'],
[b'sec-websocket-key', b'gnjFTRgXZqbLLbtArAy/2w=='],
[b'x-forwarded-proto', b'https'],
[ b'cookie',
b'_ga=GA1.2.1566485573.1481795145; _pk_id.1.5643=7983629406bf1d80.1481807462.1.1465807462.1481832162.; fbm_300453640081362=base_domain=.chipta.com; returningVisitor=1; fblo_300457561081362=y; csrftoken=TZmxiC7iIJuIpG01tVBWvIpdGSzkt0M5oYYflvP0R2XbGSNyotu3PxulZdKxR2je; chipta-name-change-popup-seen=1; sessionid=w6co0t54sddct0dajos9htrbaprkunl15; PHPSESSID=qa7toehr7hxogu6sog485ksq20'],
[b'cache-control', b'no-cache']]
So my question is, is there support for token authentication? If so, where can I find the docs and otherwise, my issue is the lack thereof.
How should we move forward from here?
Issue Analytics
- State:
- Created 7 years ago
- Comments:30 (4 by maintainers)
channels dont support token auth, but i create one mixin for this
https://gist.github.com/leonardoo/9574251b3c7eefccd84fc38905110ce4
The decorator is only needed on ws_connect:
we’re using django-rest-framework and the token is received in the app via an earlier authentication request to their
/auth-token
view.just add token=<auth_token> in the querystring like so:
wss://www.website.com/socket/group?token=65asd4f32a4sdf34asf3as54d
and the decorator will pick up on it.If you’re not using django-rest-framework you can consume the querystring in your own way. Read the rest_token_user decorator for how to get it.