Expecting to get "non_field_errors: Unable to log in with provided credentials", but not getting it - django

Expectation: when wrong login credentials are provided, "non_field_errors: Unable to log in with provided credentials" is returned, such as below (screenshot from a tutorial which I'm following verbatim)
Reality: instead I'm getting the error below.
This gets printed to the console:
POST http://127.0.0.1:8000/api/v1/token/login 400 (Bad Request)
Interestingly I get this same error when I try to create users with passwords that are too short. I'm not having any issues with axios or the server when I provide the right credentials for log in, or use passwords of sufficient length when creating new users. When trying to catch errors such as these that I'm failing to get the expected result.
My code for catching the error is the same as in the tutorial:
methods: {
submitForm() {
axios.defaults.headers.common['Authorization'] = ''
localStorage.removeItem('token')
const formData = {
username: this.username,
password: this.password
}
axios
.post('/api/v1/token/login', formData)
.then(response => {
const token = response.data.auth_token
this.$store.commit('setToken', token)
axios.defaults.headers.common['Authorization'] = 'Token ' + token
localStorage.setItem('token', token)
this.$router.push('/dashboard/my-account')
})
.catch(error => {
if (error.response) {
for (const property in error.response) {
this.errors.push(`${property}: ${error.response.data[property]}`)
}
} else if (error.message) {
this.errors.push('Something went wrong. Please try again!')
}
})
}
}
Is there something in the server settings that I should change?
I'm using Django, rest framework, and djoser.

Don't know if you're using a custom exception handler in Django rest framework but it looks like the issue could be from the way you're handling the error in your frontend application.
You can handle the errors like this.
methods: {
submitForm() {
axios.defaults.headers.common['Authorization'] = ''
localStorage.removeItem('token')
const formData = {
username: this.username,
password: this.password
}
axios
.post('/api/v1/token/login', formData)
.then(response => {
const token = response.data.auth_token
this.$store.commit('setToken', token)
axios.defaults.headers.common['Authorization'] = 'Token ' + token
localStorage.setItem('token', token)
this.$router.push('/dashboard/my-account')
})
.catch(error => {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
})
}
Can be found here

Related

Twitter_api_v2 reply to a tweet example

Could anyone Show me an example of your finished Parameters and Endpoint for a Twitter Reply maybe with a Screenshot? Because i dont understand exactly what to type in my Params and, do I got to change anything in the Pre-request Script?
Kind regards Alex
For the Params for https://api.twitter.com/2/tweets I tried:
Key : in_reply_to
Value : tweet_id
And the Result was "errors"
"message": "The query Parameters [in_reply_to] is not one of [expantions,tweet.fields,media.fields,poll.fields,place.fields,user.fields]"
"title":"Invalid Request"
"detail": "One or more Parameters to your request Was invalid.",
"type":"https://api.twitter.com/2/problems/invalid-request"
From the twitter's documentation
query parameter ids is required. You missed that parameter.
I will get tweet this demo
https://twitter.com/pascal_bornet/status/1604754709000200193
BY Postman
Full code by node.js
#1 Get an access token by API Key and API secret
#2 Get text by access token
Credential in config.json
{
"API_KEY" : "7hK your API Key GND",
"API_KEY_SECRET" : "Zr4 your API Key secret 0qX0"
}
Save as get-tweet.js
const axios = require('axios')
const config = require('./config.json');
const getAccessToken = async () => {
try {
const resp = await axios.post(
'https://api.twitter.com/oauth2/token',
'',
{
params: {
'grant_type': 'client_credentials'
},
auth: {
username: config.API_KEY,
password: config.API_KEY_SECRET
}
}
);
// console.log(resp.data);
return Promise.resolve(resp.data.access_token);
} catch (err) {
// Handle Error Here
console.error(err);
return Promise.reject(err);
}
};
const getTweetText = async (token, tweet_id) => {
try {
const resp = await axios.get(
`https://api.twitter.com/2/tweets?ids=${tweet_id}`,
{
headers: {
'Authorization': 'Bearer '+ token,
}
}
);
return Promise.resolve(resp.data);
} catch (err) {
// Handle Error Here
console.error(err);
return Promise.reject(err);
}
};
getAccessToken()
.then((token) => {
console.log(token);
getTweetText(token, '1604754709000200193')
.then((result) => {
console.log(result.data[0].text);
})
})
Get Result
$ node get-tweet.js
AAAAAksadf--very long access token in here ----JlIMJIIse
Is this the future of Christmas shopping?
Credit: Nike
#innovation #AR # VR #AugmentedReality https://~~~

No HTTP resource was found that matches the request URI hen revoking grants

I have written a function to revoke grants issued for a boundlock as shown in the code snipped below:
For context, I first run a query to get all grants, and then use the ip
UserID to get the specific grant that I want to revoke:
async revokeGrant (user) {
const token = await this.getAuthorizationCodeToken(this.refreshToken)
try {
const { data: allGrants } = await axios.get(
`${this.baseUrl}/owners/${this.operatorAccountId}/grants`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
const targetGrant = allGrants.find(grant => grant.contact.ipUserId === user.userId)
// revoke grant after getting it from above
const revokeResponse = await axios.post(
`${this.baseUrl}/owners/${this.operatorAccountId}/grants/${targetGrant.id}/revoke`,
{
dryRun: true
},
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
console.log('revokeResponse:', revokeResponse)
} catch (error) {
throw errors.customError(
error.response.data,
platform.responseCodes.InternalServer,
'Device Error',
false
)
}
}
I however keep running into an error:
Message: "No HTTP resource was found that matches the request URI 'https://tapkey-prod-main-rs.azurewebsites.net/api/v1/owners/*********/grants/*********/revoke'."
}
},
isAxiosError: true,
toJSON: [Function]
}
For revoking a grant the dryRun query parameter has to be added:
https://tapkey-prod-main-rs.azurewebsites.net/api/v1/owners/*********/grants/*********/revoke?dryRun=false
For more details please have a look at
https://developers.tapkey.io/openapi/tapkey_management_api_v1/#/Grants/Grants_RevokeById
Info:
The dryRun parameter is required. If omitted, the request will fail.
Please don't use tapkey-prod-main-rs.azurewebsites.net as baseUri as this is not a public hostname and might removed or changed without any notice.

What does JWT being stateless really means?

Hi and thanks in advance,
I've successfully setup JWT authentication using django-rest-framework-simplejwt and React but I'm still very confused about the advantages and specifically database hits.
I'm using simplejwt with ROTATE_REFRESH_TOKENS': True 'BLACKLIST_AFTER_ROTATION': True, when my access_token expire I ask for a new one through /api/token/refresh and it blacklist old tokens, I'm using axios interceptors to perform that automatically.
But in my understanding the benefits of JWt is that they are stateless, meaning I don't have to hit the user database table everytime I want to make an a request that needs authentication permission.
The problem is even with a simple view like this :
class IsConnecteddAPI(APIView):
permission_classes = [permissions.IsAuthenticated]
def get(self, request, *args, **kwargs):
data = "You seem to be connected"
return Response(data, status=status.HTTP_200_OK)
using django-silk I see that it still performs 1 query to my user table when I call it with a valid access token, is that normal ? If so why do we say that JWT are stateless ? I'm really confused.
That's my axios code if needed :
import axios from "axios";
const baseURL = "http://localhost:5000";
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
Authorization: localStorage.getItem("accesstoken")
? "JWT " + localStorage.getItem("accesstoken")
: null,
"Content-Type": "application/json",
accept: "application/json",
},
});
const axioAnonymousInstance = axios.create({
baseURL: baseURL,
timeout: 5000,
headers: {
"Content-Type": "application/json",
accept: "application/json",
},
});
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async function (error) {
const originalRequest = error.config;
if (typeof error.response === "undefined") {
alert(
"A server/network error occurred. " +
"Looks like CORS might be the problem. " +
"Sorry about this - we will get it fixed shortly."
);
return Promise.reject(error);
}
if (
error.response.status === 401 &&
originalRequest.url === baseURL + "token/refresh/"
) {
window.location.href = "/login/";
return Promise.reject(error);
}
if (
error.response.data.code === "token_not_valid" &&
error.response.status === 401 &&
error.response.statusText === "Unauthorized"
) {
const refreshToken = localStorage.getItem("refreshtoken");
if (refreshToken) {
const tokenParts = JSON.parse(atob(refreshToken.split(".")[1]));
// exp date in token is expressed in seconds, while now() returns milliseconds:
const now = Math.ceil(Date.now() / 1000);
console.log(tokenParts.exp);
if (tokenParts.exp > now) {
return axioAnonymousInstance
.post("/api/token/refresh/", { refresh: refreshToken })
.then((response) => {
localStorage.setItem("accesstoken", response.data.access);
localStorage.setItem("refreshtoken", response.data.refresh);
axiosInstance.defaults.headers["Authorization"] =
"JWT " + response.data.access;
originalRequest.headers["Authorization"] =
"JWT " + response.data.access;
return axiosInstance(originalRequest);
})
.catch((err) => {
// redirect ro /login here if wanted
console.log("axios Safe Instance error");
console.log(err);
// window.location.href = "/login/";
});
} else {
console.log("Refresh token is expired", tokenParts.exp, now);
window.location.href = "/login/";
}
} else {
console.log("Refresh token not available.");
window.location.href = "/login/";
}
}
// specific error handling done elsewhere
return Promise.reject(error);
}
);
export { axiosInstance, axioAnonymousInstance };
( I know I shouldn't use localStorage but whatever )
and I would typically just call this function to make the simple request to the view written above :
const IsConnected = () => {
axiosInstance
.get("/api/is_connected/")
.then((response) => {
if (response.status === 200) {
console.log(response.data);
console.log("Is connected : CONNECTED ");
} else {
console.log("IS connected : not connected");
}
})
.catch((error) => {
console.log("Is connected : NOT CONNECTED");
console.log(error);
});
};
Without the specifics of the exact query hit your db, it's hard to tell what is happening (the db query must have originated from a middleware because there's nothing in your code that does it, and I suspect it's django's CsrfViewMiddleware). However, as for your question of JWT being stateless, I suggest you to take a look at the official introduction.
Basically, what happens with a JWT is that your server performs a signature verification on the token using your server's secret key (please beware of some problems). If the verification passes, then the data stored inside the JWT is trusted and read as is, which is why no database query is necessary. Of course, this does mean that your user will know exactly what is stored inside their token because the data is a simple base64 encoded JSON object.

Angular 5 unit testing http response

I'm trying to unit test my http.get/post/etc responses.
I found this tutorial that was extremely helpful: https://medium.com/spektrakel-blog/angular-testing-snippets-httpclient-d1dc2f035eb8
Going through and following that, I've configured my unit tests and I'm able to get everything working, but there's one part that I have that is inconsistent with the tutorial...
In the tutorial, it shows to test the service login function like this:
it(`should emit 'true' for 200 Ok`, async(inject([HttpClientFeatureService, HttpTestingController],
(service: HttpClientFeatureService, backend: HttpTestingController) => {
service.login('foo', 'bar').subscribe((next) => {
expect(next).toBeTruthy();
});
backend.expectOne('auth/login').flush(null, { status: 200, statusText: 'Ok' });
})));
And here's the actual method on the service that is being tested:
login(user: string, password: string): Observable<boolean> {
const body = new HttpParams()
.set(`user`, user)
.set(`password`, password);
const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });
return this.http.post(`auth/login`, body.toString(), { headers, observe: 'response' })
.map((res: HttpResponse<Object>) => res.ok)
.catch((err: any) => Observable.of(false));
}
Here's my login function:
login(username: string, password: string): Observable<any> {
this.loggingService.log('LoginService | login | username: ' + username + '; password: xxxxx');
return this.http.post(this.loginUrl, { username: username, password: password })
.map((response: any) => {
console.log('response: ' + JSON.stringify(response));
if (response && response.length > 0) {
return response;
} else {
return this.parseErrorResponse(response);
}
});
}
And here's my unit test:
it('login should return a valid JWT', async(inject([LoginService, HttpTestingController], (service: LoginService, backend: HttpTestingController) => {
service.login('user', 'password').subscribe((next) => {
expect(next).toEqual('asdfasdfasdf');
});
backend.expectOne(environment.authenticationServiceBaseUrl + 'api/login')
.flush('asdfasdfasdf', { status: 200, statusText: 'Ok' });
})));
You'll notice the difference here is in the map response section. My version is getting back just a string from the unit test's http.post call, while the example shows that it's returning an HttpResponse object and is just checking that the statusText property is equal to 'Ok'.
Why is my version returning just the string, while the examples version is returning the actual HttpResponse (which includes status and statusText)? I WANT the tutorial version here...
The example shows that it returns null in the body of the response via the flush function call, while I had to add my dummy JWT value in there in order to get my test to pass. Even when I specify that as null to be like the test, then the response that I get in the unit test is null.
Where am I going wrong here?
The tutorial uses observe: 'response', which means that events emitted by the returned observable are responses, and not just the body.
This is covered in the http guide.

AWS-Cognito bot prevention with google reCaptcha

My problem is the POST-Request if the user is a bot or human.
It's not possible to send the request form Client-side, otherwise u will get an error on the OPTIONS request:" (response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource)", that's because the request is only possible from Server-Side.
In AWS-Cognito there is a way to use a pre authentication function to check something like that, but I couldn't find a way to get my response element into the function.
So my question is: Is there a way to implement Google recaptcha on AWS Cognito?
You can send this as validationData in the signup request and perform the recaptcha verify logic in a trigger SNS Lambda
Here is a snippet using the AWS Amplify library, excuse the typescript:
Client
class AuthService {
...
public signUp(
emailAddress: string,
phoneNumber: string,
password: string,
recaptchaToken: string
): Observable<ISignUpResult> {
const recaptchaTokenAttributeData: ICognitoUserAttributeData = {
Name: 'recaptchaToken',
Value: recaptchaToken
};
const signupParams: SignUpParams = {
username: emailAddress,
password,
attributes: {
'email': emailAddress,
'phone_number': phoneNumber
},
validationData: [
new CognitoUserAttribute(recaptchaTokenAttributeData)
]
};
return fromPromise(Auth.signUp(signupParams));
}
...
}
Cognito trigger on PreSignUp SNS Lambda code
export async function validateHuman(
event: CognitoUserPoolTriggerEvent,
context: Context,
callback: Callback
): Promise<CognitoUserPoolTriggerHandler> {
try {
const recaptchaToken: string = event.request.validationData.recaptchaToken;
console.log(recaptchaToken);
const isHuman: boolean = await googleRecaptcha.verify({response: recaptchaToken}, (error: Error) => {
if (error) {
console.error(error);
return false;
}
return true;
});
if (!isHuman) {
throw new Error('Not human');
}
callback(null, event);
return;
} catch (error) {
console.error(error);
callback(null, new Response(INTERNAL_SERVER_ERROR, {message: 'Something went wrong'}));
return;
}
}