Verify reCaptcha Token API Platform - vue.js

I am hoping some of you can give me the best practice on how to verify my reCaptcha token on the server.
I have a Symfony 6 app with API Platform. I have defined some entities as API Resources, so I can POST data. On the front end I am using Vue with axios to POST to the specific end points.
I would like to verify the reCaptcha token, before the data from my form is posted, and came up with the below 3 options (Not really sure if any of these are the correct way to go about this)
Create a separate end point for reCaptcha, that I post data to and depending on the response run axios post request for form or not.
Create an up mapped property on the entities I want to use reCaptcha with and set a custom validator on this that validates if the response on token is success. I can then send the reCaptcha token as part of the post request.
Create an event listener for PRE_POST and somehow validate there???
I'm not sure if I'm on the right track with any of the above, the documentation I have been able to find is pretty non existent.
I would really appreciate being pointed in the right direction, or perhaps an example of best practice on this with my current set up?

For those of you coming across this with the same issue I solved it with the following steps: (I would still like to know from someone with more knowledge, if this would be considered best practice or if there is a better way).
Added an unmapped field (No #[ORM\Column annotation) to the Symfony entity I was posting data to, called reCaptchaToken. Added the set method to my denormalizationContext group.
Created ReCaptchaConstraint (class extending Constraint) and set validatedBy method to ReCaptchaConstraintValidator::class
Created ReCaptchaConstraintValidator (class extending ConstraintValidator), added HttpClientInterface to constructor and in validate method posted to recaptcha API (details of this end point can be found in reCaptcha documentation) to validate token and score. If validation failed or score too low, added violation.
Back in Symfony entity, added #[ReCaptchaConstraint] annotation to reCaptchaToken field.
Then from front end, created Vue method:
validateCaptcha() {
return new Promise((res) => {
grecaptcha.ready(() => {
grecaptcha.execute('YOUR_SITE_KEY', {action:
'addContact'}).then((token) => {
return res(token);
})
})
})
}
In .then() method of validateCaptcha() add token to my JSON object and posted to API end point normally.
Now if there is an issue with my token or score, I will get a validation violation returned from POST.
Hope this helps someone else struggling.

Related

how can i remove token from specific Api route in laravel

I use JWT token in my project and i have an Api route that i want to remove token that send from user.
I searched a lot and many people say to put my route in $except array in VerifyCsrfToken class , but it does not work.
I want this solution because if user send request with token, the result that returned is differ from result that returned without token.
///edited
I have one route without middleware and guard, in Product model i wrote a global scope that affect on is_active column.
public function apply(Builder $builder, Model $model)
{
if (Auth::guard('manager')->check()) {
return $builder;
}
if (Auth::guard('customer')->check()) {
return $builder->where('is_active', '=',true);
}
return $builder->where('is_active', '=',true);
}
if manager use this route for products, all products returned.
i want the user's role have no effect on output.
in other word i want to remove token from some api routes
I am not sure I fully understand your question.
But isn't it possible to just adequately add one layer of middleware and do your filtering there?
So you could check if the user has a token or not and react accordingly (like forwarding the user on a specific route).
In case that may help, you can find a few middleware related videos here explaining how it works.
VerifyCsrToken is for CSRF and it's different with JWT token.
In this situation you have 2 different solution:
When your user is sending JWT token, It means your user was authenticated, and you can get user's object and send proper response.
You could make 2 different controller, and two routes, one of them for without token and another one with token, And according to user request, make your proper response.

How do I get Swagger UI to let me provide authentication header?

I used Luminus, along with reitit and swagger-ui to generate a page that lets me try out my Luminus API. I can just enter my API request body and submit to test my API.
Now I have added authentication using buddy and my API requires a token to be passed in the header of the request, or else it rejects the request as forbidden.
I'm trying to get an "Authorization" headers field to magically appear in my UI so that I can enter a JWT token string and test my API. This must be a very common requirement for anyone creating an API using reitit, but I can't figure out how to do it.
I went searching around and found this reitit issues page, which includes the text...
Header params are declared as lower-case strings {:headers {"authorization" string?}} which would match exactly what Ring provides us. (Could still HTTP-Header-Case them for documentation.)
...and suggests the setup below...
:get {:summary "list offers"
:parameters
{:headers
{"authorization" string?}}
... etc
Doing that didn't get me any way to authenticate. So, I found this discussion and edited my routes by adding the following after :summary and :parameters in the above route...
:middleware [authenticated?]
:swagger {:security [:apiKey]}
After adding that, I get this...
...which looks like I'm on the right track, but I still have no way of entering my token in the auth header.
As I said, everything is working with curl... Just that swagger isn't showing any way to add auth header. Anybody know how to get Swagger UI to play along in this scenario?
If reitit doesn't support this, then how are people using Swagger UI for authenticated requests?
Any help would be appreciated!
OK. Solved it.
At the root of my API routes (encapsulating all of the routes where I might end up using this authentication), I add :securityDefinitions.
["/api"
{:swagger {:id ::api
:securityDefinitions {:apiAuth
{:type "apiKey"
:name "Authorization"
:in "header"
}}}
Inside the specific route:
:middleware [authenticated?]
:swagger {:security [{:apiAuth []}]}

Invalid Scope for BigCommerce Oauth for my app - store_v2_transactions_read_only

My app is an approved hidden app in BigCommerce that has all of the scopes selected in the MyApp Technical page. Unfortunately, when I try to oAuth into a user, the following scope 'store_v2_transactions_read_only' returns an 'invalid scope' message. If I take that scope out, the other scopes (for read_only orders, customers, etc.) work fine and I can successfully connect an account using Oauth with my app.
The scope 'store_v2_transactions_read_only' is found in the documentation in the list of scopes here: https://developer.bigcommerce.com/api/#oauth-scopes96. But making the request to connect an account using that scope returns 'invalid_scope' and I can't access user transaction data. Again, all other scopes work, and I have them all selected in the app technical page in the developer portal.
Working in node and using axios to get the token with the oauth code. This list of scopes works:
scope: 'store_v2_customers_read_only store_v2_information_read_only store_v2_orders_read_only store_v2_products_read_only'
The moment I add store_v2_transactions_read_only it returns 'invalid scope', even thought that is the string stated in the docs. It is the same error that shows if I misspell any of the scopes.
Make sure that you're passing in the context in your query string. At the time of writing the API will send back an Invalid scope(s). error seemingly only when you request store_v2_transactions_read_only without this query param. Other scopes seem to work fine, as you've noticed, if this param is not sent.
Can't comment, because I don't have 50 karma, but adding the context to the POST call in postman from the correct answer fixed this issue for me. I had been dealing with it for some time and there isn't a lot of documentation on the BigCommerce side in other forum posts.
I am using the x-www-form-urlencoded params with:
KEY: context
VALUE: stores/abcdefg
The abcdefg is the actual store number/id in the exact format it came in from the callback.

JwtBearerAuthentication doesnt return 403 Forbidden, always returns 401 Unauthorized

If ClaimsIdentity set through JwtBearerAuthentication middleware doesnt have enough roles required through
[Authorize(Roles="whateverrole")]
it returns 401 instead of 403.
I am struggling with this in asp.net core web api whole night. I have also seen this question on stackoverflow but i havent seen any solution i could make work. The order of registering middleware nor AutomaticChallange setting did the job.
I dont know if i am missing something but it seems shocking that this hasn't been solved properly for years. It is so annoying.
Is there any normal, usual, non-workaround, non-hack way of solving this?
UPDATE (in response to comment from #juunas)
I have tried that and roles are mapped correctly from Claims.
So, if i remove Roles requirement from attribute, for all roles that user is assigned to (in JWT token) User.IsInRole(x) returns true. So mapping works just fine.
About moving from roles based authorization to policies...can you provide some some link with some best practices, recommendations or something that you base that statement on?
I am not saying its not something to be done but would just like to understand it.
It's important to understand the difference in these to errors to understand why you will get one and not the other.
401 is for authentication. If you are getting this error then you have to ask yourself is the user logged in, or does the user have a current token provided by a valid token provider? If the token has expired or the provider is not valid then you can get a 401. If this is what you are getting then you need to check User.Identity.IsAuthenticated does this return true? Most likely it returns false.
403 is for authorization. This would mean the user has a valid token, but the token they have does not give them access to the resource they are requesting. This is where you would want to check User.IsInRole() and it would return false.
If you're getting 401 it means that the user hasn't been authenticated i.e. they have not logged in, their login was invalid, the token has expired... etc. As far as your application is concerned the user hasn't proved they are who they say they are yet.
Edit: Apologies for assuming the user wasn't Authenicated, I didn't see where you stated that they where in your first post. It's hard to help without seeing code but my next guess is that the Claims check hasn't been added to the services pipeline.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("whateverrole", policy => policy.RequireClaim("whateverrole"));
});
}
This is in your Startup.cs. MS doc is here https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims
Last update: Simply put using the default Authorize attribute tag you can't change it. MS designs I this way due to the number of layers in the pipeline that could impact authentication. I was unaware of this because I use a custom Authorize attribute and forgot that I over wrote the way it handled status codes.
However I found a nice solution that might suite your needs https://github.com/aspnet/Security/issues/872#issuecomment-232624106
It adds an error page to the pipeline prior to the app.UseMvc() that redirects authentication errors to an error page that returns the correct status code.

vue-resource and JSONP working example

I'm struggling to make JSONP request using vue-resource. Can anybody provide some working examples demonstrating the proper way of defining jsonp callback, handling the call within Vue component and so on.
Thanks
**EDIT:**For other fellows, let’s clarify the situation a bit. What was the point - I have a non-authenticated user on the site and I wanted to let him do some action that requires authentication (create post e.g.). However, at the very end of creating post I wanted to show him sign-in modal window, let him log in using social oAuth providers and on successful login, let the post being approved and so on. Problem was that this call from the front-end toward different domains (social providers) was blocked (CORS issue) and than I tried to use JSONP to overcome the obstacle. Trying to setup JSONP call had spent a really lot of my time and finally I decided to go with totally different approach:
At the end of the process of creating the post, a cookie is created, caring the info what was the action that was interrupted with all necessary details. After that, a login modal is shown. Whole login process is done from the server side, and at the end, when identity of an user is confirmed, redirect to initial page is made. Further on, cookie is checked and based on the data, interrupted action continues execution successfully since the user is authenticated now.
#bryceadams thanks again for the answer!
How you handle it in your component will depend on your implementation, but typically it's done in a method - like if you had a form and then on submitting the form you called a method that made a JSONP request.
Here's an example call. Note that the important part is the jsonp option where you set the callback. This can vary based on where you're making the request to. Often it will be callback, but in my case I was working with MailChimp where it was c.
var options = {
jsonp: 'c'
}
this.$http.jsonp('https://website.com', options).then(function(data){
console.log(data.json());
}, function(error) {
// handle errors
});