Using dj-rest-auth for user auth and registration on my react app.
Got login and logout to work using api endpoints in the docs.
Failing to register a user, getting HTTP bad request 400. Reading on the web, explains that there's something wrong with my request but cannot figure what.
EDIT: Tried insomina to simulate POST registration response and got error on a Django's side:
ConnectionRefusedError at /api/dj-rest-auth/registration/
[Errno 61] Connection refused
register.js
fetch('/api/dj-rest-auth/registration/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
user: 'alalala',
password1: '1234',
password2: '1234',
email: 'ala#gmail.com',
})
})
.then(res => {
res.json()
})
settings.py
SITE_ID = 1
CORS_ORIGIN_ALLOW_ALL = True
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
]
}
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'api.serializers.CustomRegisterSerializer'
}
INSTALLED_APPS = [
#local
'api',
# 3'rd party apps
'rest_framework',
'corsheaders',
'rest_framework.authtoken',
'dj_rest_auth',
'allauth',
'allauth.account',
'allauth.socialaccount',
'dj_rest_auth.registration',
# added django but it disable admin login logout pages
'django.contrib.sites',
# django default...
]
The issue was in the settings, in config of drf auth, in this case it would work with:
ACCOUNT_USERNAME_REQUIRED = True
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
ACCOUNT_AUTHENTICATION_METHOD = 'username'
Related
So, I'm having a SPA which has Okta implemented for authentication. According to the Okta policy that is set up in place, the user(s) log in with credentials (email and password) and then are prompted to validate with a magic link or code (both sent to their primary email address). I'm trying to get around this and programmatically login through API
What I've tried so far:
a POST Request to the /api/v1/authn with the username and password (which returns a session token)
then a GET request to /oauth2/default/v1/authorize with the clientID,sessionToken,redirectUri,scope which should return the access and id tokens from my understanding...
This last request just redirect back to the login page.
Cypress.Commands.add('oktaLogin', () => {
const optionsSessionToken = {
method: 'POST',
url: `https://${Cypress.env('okta_domain')}/api/v1/authn`,
body: {
username: Cypress.env('okta_username'),
password: Cypress.env('okta_password'),
options: {
warnBeforePasswordExpired: 'true'
}
}
}
cy.request(optionsSessionToken).then(response => {
const sessionToken = response.body.sessionToken;
const qs = {
client_id: Cypress.env('okta_clientid'),
redirect_uri: `https://${Cypress.env('baseURL')}/callback`,
code_challenge_method: 'S256',
responseType: ['id_token','token'],
scope: ['openid', 'profile', 'email'],
sessionToken: sessionToken,
}
cy.request({
method: 'GET',
url: `https://${Cypress.env('okta_domain')}/oauth2/default/v1/authorize`,
form: true,
followRedirect: true,
qs: qs
}).then(response2 => {
//tokens should be available here?
cy.log(response2.body)}) //returns HTML back to login.
});
})
am very new to Pact-js and contract testing I'll try my best to explain my issue.
for now, I am only trying to generate the consumer contract
here is my pact provider:
export const provider = new Pact({
consumer: 'Users',
provider: 'UsersService',
port: 1234,
log: path.resolve(process.cwd(), 'logs', 'pact.log'),
pactfileWriteMode: 'overwrite',
logLevel: "DEBUG",
dir: path.resolve(process.cwd(), 'pacts'),
});
and here is my test:
jest.mock("axios");
const EXPECTED_BODY = {...}
describe("Pact tests axios", () => {
describe("/GET login", () => {
beforeAll(() => provider.setup());
afterEach(()=> provider.verify())
afterAll(() => provider.finalize());
it("should login user and response with user object", async () => {
await provider.addInteraction({
state: 'user logged', uponReceiving: 'request logged user', withRequest: {
method: 'GET',
path: '/users/login',
body: {username: "test", password: "11223344"},
}, willRespondWith: {
status: 200, headers: {
'Content-Type': 'application/json',
}, body: eachLike(EXPECTED_BODY),
},
});
axios.get.mockResolvedValueOnce(EXPECTED_BODY);
const loggedUser = await loginUser("test", "11223344")
expect(axios.get).toHaveBeenCalledTimes(1)
expect(axios.get).toHaveBeenLastCalledWith("http://localhost:8080/users/login", {"headers": {"Content-Type": "application/json"}, "params": {"password": "11223344", "username": "test"}})
expect(loggedUser).toEqual(EXPECTED_BODY)
})
});
})
I should say that my original request takes two parameters username and password and returns an object containing all that user's information of course the user exists if not it returns null
here is the API call function if needed:
export default async function loginUser(username, password) {
try{
return await axios.get(("http://localhost:8080/users/login"), {
headers: {
"Content-Type": "application/json"
},
params: {
username: username,
password: password
}
})
}catch (e){
return null
}
}
Pact expects you to actually make the call to the endpoint you're mocking in Pact.
Missing requests: GET /users/login
This error says "you said you'd make a GET call to /users/login but I didn't receive it".
jest.mock("axios");
This looks like you're mocking the HTTP client Axios. Now you have a mock for the thing that needs to send requests to the Pact Mock.
In a Pact test, think of it as a unit tests for your API client code. The actual request needs to be sent to the Pact Mock and Pact will check the correct request was made, and return back the mocked response.
So the solution is simple:
Remove all of the axios mocking
Provide a way to modify the API target for loginUser
Configure your API client to send the request to localhost:1234 instead of the real thing before running the tests
(NOTE: you can have pact find a free port dynamically by not setting the port option, and take the host from the response from the setup() call)
I am very new to the Google OAUth2.0 authentication and thus my question sounds like dumb. However, I am stuck with this problem quite a time and need your input to solve it.
I was integrating the Globus login within my app. Globus login using Google OAuth-2 protocol for authentication. According to the Globus Auth developer guide, I successfully redirect the app to their authorization service, the user can put their credential to authenticate, and the app receives the code returned from the Globus Auth server upon successful authentication. Next step is sending the code to the Token endpoint to get the access token. I used the following code:
var querystring = require('querystring');
export const logInGlobus = (payload) => {
let tokenUri = encodeURIComponent(payload.redirect_uri);
let client_id = 'out app client id'
let client_secret = 'client secret generated for authentication'
let cred = btoa(client_secret);
return axios.post('https://auth.globus.org/v2/oauth2/token',
querystring.stringify({
grant_type: 'authorization_code',
code: payload.code,
redirect_uri: tokenUri,
client_id: client_id
}),
{
headers:{
Authorization: 'Basic '+ cred,
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => {
return{
res: response,
success: true
}
})
.catch(err => {
return{
res: err,
success: false
}
})
}
I am getting 401 {"error":"invalid_client"} code for this post request from the server. What am I missing?
N.B: I have tried without client secret, client id, not encoding redirect URL. No luck so far>
I would really appreciate your effort if you show me some light. Thanks for your time.
====Edited====
The error from the console at the browser is attached
I solved the problem. I had to put the client secret at the body of the post request. The following code resolves my problem.
var querystring = require('querystring');
export const logInGlobus = (payload) => {
let client_id = 'app client id'
let client_secret = 'client secret generated for authentication'
return axios.post('https://auth.globus.org/v2/oauth2/token',
querystring.stringify({
grant_type: 'authorization_code',
code: payload.code,
redirect_uri: payload.redirect_uri,
client_id: client_id,
client_secret: client_secret
}),
{
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response => {
return{
res: response,
success: true
}
})
.catch(err => {
return{
res: err,
success: false
}
})
}
I have the Vue app and the Django rest framework api separately.
One on localhost:8080 (vue app) and the rest api on localhost:8000.
So, I created an APIView that is supposed to log the user in when they make a post request:
class LoginUserAPIView(APIView):
permission_classes = () # login should be accessed by anyone, no restrictions.
def post(self, request, format=None):
username = request.data['username']
password = request.data['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
user = UserSerializer(user)
return Response({'success': 'Logged in', 'user': user.data})
return Response({'wrong': 'username or password not correct, try again'}, status=status.HTTP_401_UNAUTHORIZED)
And I was trying to get the user session from django with axios:
login() {
this.isLoading = true;
return axios({
method: 'post',
url: 'http://localhost:8000/api/login_user',
data: {
username: this.name,
password: this.password
},
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
this.$store.commit('loginAuth', true); // setting isAuth to true in vuex store.
this.$store.commit('setUser', response.data.user); // to access the user object since I don't use django templates
this.$router.push({name: 'page'}); // redirect to random test page that requires authorization so I can see if everything went fine.
})
.catch(err => {
console.error(err);
if (err.response.status == 401) {
alert(err.response.data.wrong);
this.isLoading = false;
}
})
but I was naive and I thought this would work, so when I checked the vue app for any cookies or sessions, nothing.
How could I set user session for a separate vue app?
Thanks in advance, I apologize for my lack of knowledge.
I have been googling the all of the interwebs and I just can't find the solution to my problem. I'm trying to make an application using ElectronJS and I need to send an HTTP request with authentication basic header but I just can't get it to work.
Here's my code:
export default {
name: 'home',
data: function() {
return {token: ''}
},
methods: {
fetchData() {
this.$http({
method: 'get',
url: 'URL_TO_SERVER',
auth: {
username: 'USERNAME',
password: 'PASSWORD'
},
headers: {
'Access-Control-Allow-Origin': '*',
credentials: 'same-origin',
},
withCredentials: true,
}).then((response) => {
console.log(response.data);
}).catch((error) => {
console.log('ERROR: '+ error.response.data);
});
}
}
}
I am getting the following error:
XMLHttpRequest cannot load (URL_TO_SERVER). Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9080' is therefore not allowed access. The response had HTTP status code 401.
Does anyone have any idea's what could be my next step to fixing this?
If i do the same info with a REST client it will return the correct values, just not in ElectronJS
After building the application in to an EXE, it worked, just doesnt work in npm run dev.