I am able to get the jwt token for the get, post, put requests using **get_jwt_identity()*.
But how can i acquire it for flask-sockets.
def handle_message():
emit('message_activated', {'data': 'my data', 'count': 0})
socketio.on_event('message', handle_message)
Assuming you are using the JavaScript Socket.IO client, you can use the extraHeaders option to pass custom headers. Example:
var socket = io("http://localhost:5000", {
extraHeaders: {
"X-My-Auth": "your-token-here"
}
});
Of course you can replace the X-My-Auth header name with the header that you are using.
In the server, authentication for Flask-SocketIO events is performed only when the client connects. There is no need to authenticate every single event because there is a permanent connection between the client and the server. Here is an example connection handler:
#socketio.event
def connect():
token = request.headers['X-My-Auth']
if not verify_token(token):
return False
# user is authenticated, proceed normally from here on
Related
I am building an application. The client is built with Next.js and the backend with Django and Django REST framework.
In this application, I would like to have social login.
So far, my situation is this.
I have set up the OAuth on the Google dashboard
On the client, I am using next-auth - The client is successfully calling Google and getting an access token from there.
On the client, the callback that runs after getting the access token from Google makes a call my Django API.
I have set up the backend with dj_rest_auth - My settings are almost identical to the ones described here.
Once the client callback runs and calls my Django API with the access token from Google, I successfully get on the client an access token and a refresh token.
If it is a new user loggin in the first time, a new user is created in Djangos DB
const response = await fetch(`${djangoAPIurl}/api/social/login/google/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
access_token: accessToken,
id_token: idToken
})
});
const data = await response.json();
const { access_token, refresh_token } = data;
Both access_token and refresh_token are defined and appear to be valid tokens.
So far, everything happens as expected. My issue appears after this point.
In my api, I have another view defined.
#api_view(['GET'])
#authentication_classes([SessionAuthentication, BasicAuthentication, TokenAuthentication])
#permission_classes([IsAuthenticated])
def test_view(request):
current_user = request.user
print('current_user.auth: ', current_user.is_authenticated)
response = JsonResponse({"received": True})
return response
From my client, I am attempting to call this view in the following way.
const response = await fetch(`${djangoAPIurl}/api/test/test_view/`, {
headers: new Headers({
Authorization: `Bearer ${session.accessToken}`
})
});
The header is constructed correctly, with session.accessToken being the value I got from the api/social/login/google/ call and the request is routed correctly, however, it fails with Forbidden 403 because the user is not authenticated. I have removed the authentication and permission decrators and the request ends up being processed by the view, and there, upon inspection of the user, it is an Anonymous user. I have also tried changing Bearer to Token, to no avail.
Do you have any advice what I might be doing wrong or missing? Have I completely missunderstood how to use the token I get back from api/social/login/google/? All advice is much appreicated!
I think this is because your secret for hashing JWTS on the client side and server side is not same. Next-Auth automatically creates a secret key for hashing jwt's and dj_rest_auth does the same, unless you explicitly tell them both to use the same secret for hashing jwts. I'm a bit late to answer this, but Hope this will help future people😁😁.
I'm using Vue in my frontend and I'm successfully calling the checkout modal and the token is being successfully created when that modal's form is sent. However, I haven't been able to actually create the charge on the backend.
It all starts with this method in my Vue component, that handles the token once the form is sent:
done ({token, args}) {
// token - is the token object
// args - is an object containing the billing and shipping address if enabled
// do stuff...
this.$refs.addBookModal.show();
$backend.createStripeCharge(token.email, token)
},
The createStripeCharge function in backend.js is the following:
createStripeCharge (email, token) {
console.log('create stripe charge called')
return $axios.post(`/resource/${email}`)
.then(response => response.data)
.catch(error => {
this.error = error.message
})
},
and this is the route in Flask:
#api_rest.route('/resource/<string:resource_id>')
class ResourceOne(Resource):
""" Unsecure Resource Class: Inherit from Resource """
def post(token, user_email):
charge = stripe.Charge.create(
customer = token.id,
amount = 2500,
currency='usd',
description='25',
recipent_email=user_email
)
However I'm getting a 500 internal server error. What am I doing wrong?
I find one problem in the ResourceOne's post method is that it has two parameters and you're passing only one at backend.js's createStripeCharge function.
(Also, it is always helpful to other SO user if you post error log here.)
Am trying to write custom middleware in the ASP.net core pipeline, as part of my invoke, would like to append/add cookie, so then next middleware in the pipeline can access those cookie.
getting compiling error on set the cookie value. Can anyone recommend work around for this.
Note: When I tried with Response.Cookie , it works but only problem is, cookie is reflecting only on next request from the browser, but I need this to be reflecting on the next middleware in the pipeline immediately after execute this.
below code snippet
public async Task Invoke(HttpContext httpContext)
{
var queryParameters = httpContext.Request.Query;
var cookies = httpContext.Request.Cookies;
if (!cookies.ContainsKey(".AspNetCore.Session")
|| cookies[".AspNetCore.Session"] != "new_key")
{
httpContext.Request.Cookies[".AspNetCore.Session"] = "new_key";
}
await _next.Invoke(httpContext);
}
You cannot use cookie's value in same request. However, you could use good old HttpContext.Items.
public async Task InvokeAsync(HttpContext context)
{
context.Request.HttpContext.Items["key"] = "Hello!";
await _next(context);
}
You then retrieve it as
var value = HttpContext.Items["key"];
In my case I have an AuthorizationHandler that performs some checks to determine the user details and whether the user is logged in. The auth handler stores some of this info in a token in the request headers, so it can be easily accessed by the controllers.
When the user is logged in, this token can be read from the HttpContext.Request.Headers in a standard controller and all is well.
When the user is not logged in, the auth handler returns failure and so the request is redirected to "/login". Sadly the token header is not preserved across the redirect, so in my LoginController the token is null.
The only way I could make the token available to both a standard controller and LoginController is to store the token in both the request headers AND response cookies. This cookie can be read from the LoginController in the HttpContext.Request.Cookies collection. I set it to be short-lived as it's only needed briefly (it'll disappear after 5 seconds)
Here is part of the code from my auth handler:
HttpRequest request = _httpContextAccessor.HttpContext.Request;
HttpResponse response = _httpContextAccessor.HttpContext.Response;
request.Headers["X-Token"] = encryptedToken;
response.Cookies.Append("TokenCookie", encryptedToken, new CookieOptions
{
MaxAge = TimeSpan.FromSeconds(5),
Secure = true,
IsEssential = true,
});
I'm doing a BrowserClient POST across domains and don't see my cookies being included.
This the response I'm getting:
When I send another POST request, I don't see the cookies being included:
Going straight to the test page, I can see the cookies being included:
The Dart code I use to make a POST:
var client = new BrowserClient();
client.post(url, body: request, headers:{"Content-Type" : "application/json", "Access-Control-Allow-Credentials":"true"}).then((res) {
if (res.statusCode == 200) {
var response = JSON.decode(res.body);
callback(response);
} else {
print(res.body);
print(res.reasonPhrase);
}
}).whenComplete(() {
client.close();
});
Not sure about the Access-Control-Allow-Credentials header I'm including, with or without it, nothing changes.
Am I missing headers on the server side that needs to be set on the response or is Dartium blocking cross-domain cookies?
More details on Information Security and the reasoning behind setting cookies via the server.
Update: Enhancement request logged: https://code.google.com/p/dart/issues/detail?id=23088
Update: Enhancement implemented, one should now be able to do var client = new BrowserClient()..withCredentials=true; based on
https://github.com/dart-lang/http/commit/9d76e5e3c08e526b12d545517860c092e089a313
For cookies being sent to CORS requests, you need to set withCredentials = true. The browser client in the http package doesn't support this argument. You can use the HttpRequest from dart:html instead.
See How to use dart-protobuf for an example.
I am exposing a webservice using eventmachine and evma_httpserver as follows:
EM.run{
puts "Query Server running on port 9000"
EM.start_server '0.0.0.0', 9000, QueryEngineHttpServer
}
I would like to make it secure, i.e., require a user name and password. I know how to do this using Sinatra, but I'm not using it for this, so I'm no sure how to proceed.
which kind of authentication do you need? Basic-auth or cookie based?
is this something that can help you ?
module QueryEngineHttpServer
include EM::HttpServer
def post_init
# if you want the connection to be encrypted with ssl
start_tls({:private_key_file => path_to_key_file,
:cert_chain_file => path_to_key_file,
:verify_peer => false})
# don't forget to call super here !
super
end
def process_http_request
# Block which fulfills the request (generate the data)
operation = proc do
# depending of which kind of auth you want you should have to parse the cookie or the 'autorization' header
auth = check_for_auth #http_cookie, #http_headers
# create the response object to be used in the EM::defer callback
resp = EM::DelegatedHttpResponse.new(self)
resp.status = auth ? 200 : 401
resp.content = 'some content here...'
resp
end
# Block which fulfills the reply (send back the data to the client)
response = proc do |reply|
reply.send_response
end
# Let the thread pool handle request
EM.defer(operation, response)
end
end