404 error while activating user in djoser (django) - authentication

I created class based view to access uid and token . Here I create one web page which have one button of activate user.
I wish to activate user that created. I am receiving the activation link via email. When I click on the link an activation page is opened. this page has a button to activate user. On click the button a post request is executed to activate user but I am getting 404 error.
Activate_User_App/views.py
import json
from common_strings import ACTIVATION_BASE_ROUTE
from django.views import View
from django.shortcuts import render
from django.http import HttpResponse
import requests
class ActivationView(View):
def get (self, request, uid, token):
print('get called in activate')
return render(request, 'activate.html')
def post (self, request, uid, token):
print('UID : ', uid)
print('Token : ', token)
payload = json.dumps({'uid': uid, 'token': token})
print("payload : " , payload)
protocol = 'https://' if request.is_secure() else 'http://'
web_url = protocol + request.get_host() + '/'
post_url = web_url + ACTIVATION_BASE_ROUTE
print('post_url : ' + post_url)
response = requests.post(post_url, data = payload)
print("response : ", response)
return HttpResponse(response.text)
Activate_User_App/urls.py:
urlpatterns = [re_path(r'^(?P<uid>[\w-]+)/(?P<token>[\w-]+)/$',ActivationView.as_view()),]
settings.py
DJOSER = {
'PASSWORD_RESET_CONFIRM_URL': AUTHENTICATION_BASE_ROUTE + 'password/reset/confirm/{uid}/{token}',
'USERNAME_RESET_CONFIRM_URL': AUTHENTICATION_BASE_ROUTE + 'username/reset/confirm/{uid}/{token}',
'ACTIVATION_URL': ACTIVATION_BASE_ROUTE + '{uid}/{token}/',
'SEND_ACTIVATION_EMAIL': True,
'SEND_CONFIRMATION_EMAIL': True,
'PASSWORD_CHANGED_EMAIL_CONFIRMATION': True,
'USERNAME_CHANGED_EMAIL_CONFIRMATION': True,
'USER_CREATE_PASSWORD_RETYPE': True, #Designed to propote good programming practice
'SET_PASSWORD_RETYPE': True, #Designed to propote good programming practice
'PASSWORD_RESET_CONFIRM_RETYPE': True, #Designed to propote good programming practice
'LOGOUT_ON_PASSWORD_CHANGE' : True, #Note : Logout only works with token based authentication. djoser 2.10
'PASSWORD_RESET_SHOW_EMAIL_NOT_FOUND': False, #Please note that setting this to True will expose information whether an email is registered in the system
'USERNAME_RESET_SHOW_EMAIL_NOT_FOUND': False, #Please note that setting this to True will expose information whether an email is registered in the system
'HIDE_USERS': True,
'token': 'djoser.serializers.TokenSerializer',
'token_create': 'djoser.serializers.TokenCreateSerializer',
'LOGIN_FIELD': 'email', #Default: User.USERNAME_FIELD where User is the model set with Django’s setting AUTH_USER_MODEL.
'SERIALIZERS': {
'user': 'user_profile.serializer.UserSerializer',
},
project/urls.py
urlpatterns = [
path(ACTIVATION_BASE_ROUTE, include('Activate_User_App.urls')),
re_path(r'^api/authentication/', include('djoser.urls')),
re_path(r'^api/authentication/', include('djoser.urls.authtoken')),
common_strings
AUTHENTICATION_BASE_ROUTE = 'authentication/user/'
ACTIVATION_BASE_ROUTE = AUTHENTICATION_BASE_ROUTE + 'activate/'
activate.html
<form action="" method="post">
{% csrf_token %}
<td ><button type="submit">Click Here For Activate Account</button></td>
</form>

Related

drf-yasg Swagger documentation does not recognize authorized users

I've set up DRF-YASG documentation for my Django project, but the endpoints that require authentication show no parameters (fields to fill) even when logged as an authorized user.
swagger ui
In fact, none of my endpoints show their respective parameter fields in the UI.
Here are my REST_FRAMEWORK settings in settings.py :
REST_FRAMEWORK = {
"NON_FIELD_ERRORS_KEY": "errors",
"DEFAULT_AUTHENTICATION_CLASSES":(
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication"
),
"DEFAULT_PERMISSON_CLASSES":(
"rest_framework.permissions.IsAuthenticated"
)
}
and urls.py:
from django.contrib import admin
from django.urls import path, include, re_path
from EmployeeApp import views
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact#snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
name='schema-json'),
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('admin/', admin.site.urls),
path('', views.api_home),
path('api/', include('EmployeeApp.urls')),
path('api/auth/', include('accounts.urls')),
]
I am using standard token authentication and here are my views.
from django.contrib.auth import authenticate
from .serializers import SignUpSerializer, UserSerializer
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
class SignUpView(generics.GenericAPIView):
serializer_class = SignUpSerializer
def post(self, request: Request):
data = request.data
serializer = self.serializer_class(data=data)
if serializer.is_valid():
serializer.save()
response = {
"message": "User Created Successfully",
"data": serializer.data
}
return Response(data=response, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
#swagger_auto_schema(request_body=UserSerializer)
def post(self, request: Request):
email = request.data.get('email')
password = request.data.get('password')
user = authenticate(email=email, password=password)
if user:
response = {
"message": "Login Successful",
"token": user.auth_token.key
}
return Response(data=response, status=status.HTTP_200_OK)
else:
return Response(data={"message": "Invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED)
def get(self, request: Request):
content = {
"user": str(request.user),
"auth": str(request.auth)
}
return Response(data=content, status=status.HTTP_200_OK)
In Postman everything works as expected, but in the Swagger documentation the authenticated user is not being recognized and the parameter fields on endpoints are missing.
Not sure if these two issues are connected, but I would apprechiate any type of helpful input on this!
I have tested the endpoints with direct Postman requests and everything works as expected.
Here is the endpoint to Create(POST) a company as a logged User:
class CompanyCreate(APIView):
permission_classes = [IsAuthenticated]
#swagger_auto_schema(
operation_summary="Create a company",
operation_description="This allows logged-in user to create a company"
)
def post(self, request):
company_name_exists = Companies.objects.filter(company_name=request.data['company_name']).exists()
if company_name_exists:
raise ValidationError("Company with the same name already exists")
data = {**request.data, 'user_id': request.auth.user_id}
serializer = CompanySerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and it's serializer:
class CompanySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = Companies
fields = ('user_id', 'company_name', 'company_description', 'company_logo')
def create(self, validated_data):
company, is_created = Companies.objects.get_or_create(
company_name=validated_data['company_name'],
company_description=validated_data['company_description'],
company_logo=validated_data['company_logo'],
user_id=validated_data['user_id'],
)
return company
I've attached `
#swagger_auto_schema(request_body=UserSerializer)
`
to my login endpoint and it gives me a filed to put the request body data in a JSON format.
enter image description here
that works, but it still does not show the Swagger UI parameter fields and the auth does not persist when I try to test endpoints that require it.

I am trying to authenticate the the USER model for Register and Login API in Django REST framework. I am getting the following error msg

"detail": "Authentication credentials were not provided."
I have tried all the available internet solutions, added the
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'knox.auth.TokenAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAdminUser',
'rest_framework.permissions.IsAuthenticated',
]
}
But nothing worked in my favor. I am adding the serilizers.py and api.py files below. Please review them and tell me if there is some other way to fix this.
Following is the serializers.py file code
from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
# User Serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
# Register Serializer
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
return user
# Login Serializer
class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Incorrect Credentials")
api.py is given as:
from rest_framework import generics, permissions
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import UserSerializer, RegisterSerializer, LoginSerializer
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
_, token = AuthToken.objects.create(user)[1]
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})
# Login API
class LoginAPI(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
_, token = AuthToken.objects.create(user)
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})
# Get User API
class UserAPI(generics.RetrieveAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
Urls.py
from django.urls import path, include
from .api import RegisterAPI, LoginAPI, UserAPI
from knox import views as knox_views
urlpatterns = [
path('api/auth/', include('knox.urls')),
path('api/auth/register', RegisterAPI.as_view()),
path('api/auth/login', LoginAPI.as_view()),
path('api/auth/user', UserAPI.as_view()),
path('api/auth/logout', knox_views.LogoutView.as_view(), name='knox_logout')
]
Please help me solve the issue. I am unable to make any post request on Postman and without Register, Login API won't work too.
To make the API public, you need to override your permissions in your settings. You should update your Views.
from rest_framework.permissions import AllowAny
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
permission_classes = [AllowAny]
authentication_classes=() # To make sure no check if you send Authorization header to server
...
Apply for your Login view too.
Update your Register view to allow non logged in since you have 'rest_framework.permissions.IsAuthenticated' as a default permission
from rest_framework.permissions import AllowAny
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
permission_classes = [AllowAny]
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
_, token = AuthToken.objects.create(user)[1]
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})

How to login to Flask App when using Locust

First time using Locust. I have a Flask App that requires user to login to access most routes.
I cant get Locust to successfully login to my Flask App.
Here is my Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED", "password": "REDACTED"},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
#task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
Here is the login function of my Flask App: (with a few debug statements added)
#users.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST': ##DEBUG
logging.debug(f"debug0: inside login func with method == POST") ##DEBUG
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
if form.validate_on_submit():
logging.debug(f"debug0.1: inside validate_on_submit") ##DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") ##DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") ##DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") ##DEBUG
return render_template('login.html', title='Login', form=form)
When i run Locust, I get this output:
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting web monitor at *:8089
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting Locust 0.11.0
[2019-09-16 18:03:14,069] Mac-mini-3.local/INFO/locust.runners: Hatching and swarming 2 clients at the rate 1 clients/s...
[2019-09-16 18:03:14,138] Mac-mini-3.local/ERROR/stderr: /Users/myuser/.local/share/virtualenvs/locustio-gB1-mbqd/lib/python3.7/site-packages/urllib3/connectionpool.py:851: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning)
[2019-09-16 18:03:14,162] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:14,183] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
[2019-09-16 18:03:14,213] Mac-mini-3.local/INFO/stdout: DEBUG list: response.status_code = 200
[2019-09-16 18:03:15,112] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:15,137] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
I'm not concerned about the 'InsecureRequestWarning' as this is because I am using a self signed cert and i have disabled verification with 'self.client.verify = False'
The csrftoken looks correct.
From the Flask App itself, I get this output:
DEBUG:user:debug0: inside login func with method == POST
INFO:flask_wtf.csrf:The CSRF token is missing.
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
So, it's hitting the login function (proven by debug0) but it's not getting into the 'form.validate_on_submit()' conditional.
So far I have spent all day on this, reading articles and trying a lot of things, ie adding the X-CSRFToken headers.
I feel I am missing something fundamental, and would really appreciate some help.
thanks,
WJ
Ok, I solved it, so thought I would share the anwser for anyone else that comes across this. As suggested by #user10788336 its is not a Locust issue.
The issue was that when POSTing to the flask route, the form was not being validated (ie form.validate() was not getting set).
So, I made two changes.
1) changed the POST to have an additional form item which i called "test-mode" and I set the value to "locust-test"
here is the new Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED",
"password": "REDACTED",
"test-mode": "locust-test"
},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
#task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
The diff between old and new is:
< {"email": "REDACTED", "password": "REDACTED"},
---
> {"email": "REDACTED",
> "password": "REDACTED",
> "test-mode": "locust-test"
> },
2) I changed my login function the Flask app:
The change is that I don't need the form to be validated, so I skip that ONLY when I detect that I am running in test-mode.
here is the new login function:
#users.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
# shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
form_is_ok = False
if request.method == 'POST':
if request.form.get('test-mode') == 'locust-test':
form_is_ok = True
else:
form_is_ok = form.validate_on_submit()
if form_is_ok:
logging.debug(f"debug0.1: inside validate_on_submit") # DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") # DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") # DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") # DEBUG
return render_template('login.html', title='Login', form=form)
The diff between old and new is:
< if form.validate_on_submit():
---
>
> # shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
> form_is_ok = False
> if request.method == 'POST':
> if request.form.get('test-mode') == 'locust-test':
> form_is_ok = True
> else:
> form_is_ok = form.validate_on_submit()
>
> if form_is_ok:
I think this is still secure ... thoughts on that?
I might add a config variable, that disables/enables this functionality.
And it works!!!!
BTW, Locust is awesome!
Hope this helps.
cheers,
WJ
Can you share the code for what the form.validate_on_submit method is expecting/validating? Chances are there is a hidden field in the login form that is acting as a dynamic token and/or you're missing a required field. Can you also share the HTML source of the login form?
I'd also be curious to see you add an additional debug statement in your login method that outputs the value of the CSRF token, to make sure it is valid, e.g.
def login(self):
print(f"DEBUG: login csrftoken = {self.csrftoken}")
response = self.client.post("/login",
{"email": "REDACTED",
"password": "REDACTED",
"test-mode": "locust-test"
},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
I'd also be curious to see if there are any error messages when you submit the form without a valid CSRF token. Does it return a 200 status code and report the invalid token?
My guess is that it's something to do with the CSRF token not being valid or handled correctly.
Is this an older or customized version of Flask login? I'm not seeing an X-CSRFToken header method in the latest version of Flask login docs at https://flask-login.readthedocs.io/en/latest/

Fetching current loggedin user using spring security

I have a problem in getting the logged in user in my spring-extjs application.I am using spring security 2.0.4.Here are the details of what i have tried.
Controller class:
#RequestMapping(value="/StaffingApplication/index.action", method = RequestMethod.GET)
public String printUser(ModelMap model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName(); //get logged in username
System.out.println(name);
model.addAttribute("username", name);
return "index.jsp";
}
login.js file
var login = new Ext.FormPanel({
labelWidth:80,
url:'j_spring_security_check',
frame:true,
title:'Please Login',
defaultType:'textfield',
width:300,
height:130,
monitorValid:true,
// Specific attributes for the text fields for username / password.
// The "name" attribute defines the name of variables sent to the server.
items:[{
fieldLabel:'Username',
name:'j_username',
allowBlank:false
},{
fieldLabel:'Password',
name:'j_password',
inputType:'password',
allowBlank:false
}],
// All the magic happens after the user clicks the button
buttons:[{
text:'Login',
formBind: true,
// Function that fires when user clicks the button
handler:function(){
login.getForm().submit({
method:'POST',
// Functions that fire (success or failure) when the server responds.
// The server would actually respond with valid JSON,
// something like: response.write "{ success: true}" or
// response.write "{ success: false, errors: { reason: 'Login failed. Try again.' }}"
// depending on the logic contained within your server script.
// If a success occurs, the user is notified with an alert messagebox,
// and when they click "OK", they are redirected to whatever page
// you define as redirect.
success:function(){
Ext.Msg.alert('Status', 'Login Successful!', function(btn, text){
if (btn == 'ok'){
window.location = 'index.action';
}
});
},
// Failure function, see comment above re: success and failure.
// You can see here, if login fails, it throws a messagebox
// at the user telling him / her as much.
failure:function(form, action){
if(action.failureType == 'server'){
obj = Ext.util.JSON.decode(action.response.responseText);
Ext.Msg.alert('Login Failed!', obj.errors.reason);
}else{
Ext.Msg.alert('Warning!', 'Authentication server is unreachable : ' + action.response.responseText);
//window.location='loginFailure.html'+action.response.responseText;
}
login.getForm().reset();
}
});
}
}]
});
On my jsp page I access it like this.
<div id="header" class="header">Options Staffing Application
<div style="" id="user-status">
<a href='<c:url value="j_spring_security_logout"/>'>Logout</a>
<h3>Username : ${username}</h3>
</div>
</div>
But I just get a blank in place of username.
When I try to print it in the controller I get the value printed,but doesn't seem to be displayed on the jsp page.Went throgh other threads but did not help.Any help would be appreciated
Thanks for the time
Sachin
You don't need to put the username into an object model because you can access it from a jsp just like the way you do in the controller class:
<h3>Username <%=SecurityContextHolder.getContext().getAuthentication().getName(); =></h3>
Or even better:
<h3>Username <sec:authentication property="name" /></h3>
But i'm not sure if you can use that taglib in Spring Security 2

Rails + Devise: redirect to a specific url upon public page Facebook Login

I have a public assessable page
"http://www.example.com/gift/5"
There is a Facebook connect button on it.
I want the user to click the Facebook connect button and then be redirected to
"http://www.example.com/gift/5/coupon"
Currently Devise/Omniauth seems to lose the session as it's authenticating the user.
I've tried sending an ajax request before I do a FB.api
FB.login(function(response) {
if (response.session) {
$.ajax({
url : '/ajax/facebook/url',
type : 'post',
data : {push_to: "/gift/5/coupon"},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
}
});
window.location = "https://graph.facebook.com/oauth/authorize?client_id=..........";
} else {
}
});
Ajax request hits
class AjaxController < ApplicationController
def ajax_facebook_url_redirect
session[:"fb_redirect_to"] = params[:push_to]
end
But I can't find the variable in either
application_controller.rb
def after_sign_in_path_for(resource)
print session[:"fb_redirect_to"]
(session[:"user.return_to"].nil?) ? "/" : session[:"user.return_to"].to_s
end
Any advice on sending the user to a specific url from a public page?
There is a new section recently added to the OmniAuth Overview docs on the Devise website that addresses this issue: https://github.com/plataformatec/devise/wiki/OmniAuth%3A-Overview
Here is the gist:
def authenticate_user!
if !current_user
# This should work, but session is lost. See https://github.com/plataformatec/devise/issues/1357
# session[:return_to] = request.fullpath
redirect_to user_omniauth_authorize_path(:google_apps, :origin => request.fullpath)
end
end
def after_sign_in_path_for(resource)
# This should work, but session is lost. See https://github.com/plataformatec/devise/issues/1357
# return_to = session[:return_to]
# session[:return_to] = nil
return_to = request.env['omniauth.origin']
stored_location_for(resource) || return_to || root_path
end