Facebook Oauth2 cannot manually open the consent dialog Vuejs - vue.js

I am trying to "Manually Build a Login Flow" according to these docs here: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
The idea is that i want to generate an one time authorization code, then send it to my back end so it can generate there the access token and then get the user data.
The docs above nicely have sections like "Invoking the Login Dialog and Setting the Redirect URL" and "Exchanging Code for an Access Token" along with the respective endpoints to hit, which is exactly what i want. So I started implementing the dialog invocation on the front end which is a vuejs app, so i can generate the authorization code to send it to my server.
Here is the code:
<script>
import axios from "axios";
export default {
methods: {
facebookAuth(){
axios.get('https://www.facebook.com/v4.0/dialog/oauth?client_id=MY_CLIENT_ID&redirect_uri=http://localhost:3000&state="I AM A STRING"', {
headers:{
'Access-Control-Allow-Origin': '*',
}
})
.then(res=>{
console.log(res);
})
}
}
};
</script>
The first issue here is that i get CORS error, even with my anticors chrome extension open. So i pass it to this proxy https://cors-anywhere.herokuapp.com/
and I manage to make it work, but no consent dialog opens. I just get a http response with an html page code as a response body.

Related

React Query uses outdated headers (old JWT token) after Keycloak refresh token

I'm pretty new in React-Native programming, but here is the context.
We are using React Query and Axios libraries in our project. As AuthManager we are using Keycloak and for the library managing auth status we have React Native Keycloak. We encounter a tedious problem with our server responding randomly 401 at our requests after a certain amount of time, bringing also to the app crash sometimes.
We reproduced the error making the Bearer Token of Keycloak expire after only 1 minute. This caused almost immediatly the 401 error and we wondered why this is happening.
Let's say we have a screen with some "Activities" and this screen is the first thing the user will see. For handling requests, in our code we use some custom hooks that reference useQuery, for example:
export function useActivities(): UseQueryResult<ActivityList> {
const { headers } = useHeaders();
return useQuery(
['activities', today.start],
() => getActivitiesList(headers), // Note 1
{
enabled: !!today.start,
}
);
}
The important point of it is that we useHeaders to get our updated headers with the Keycloak token and our realm settings. useHeaders is almost everywhere in our app.
export function useHeaders(): UseHeaders {
const { keycloak } = useKeycloak();
const KEYCLOAK_REALM = remoteConfig().getString('KEYCLOAK_REALM');
const headers = {
Authorization: `Bearer ${keycloak?.token}`,
Realm: KEYCLOAK_REALM,
};
return { headers };
}
Now, the getActivitiesList is simple as five:
async function getActivitiesList(headers: UseHeaders['headers']): Promise<ActivityList> {
const url = `${BASE_URL}${VERSION}/activities/grouped?end=${end}&start=${start}`;
// Note 2
return axios
.get(url, { headers })
.then((res) => res.data)
.catch((e) => console.error('Error fetching grouped activities:', e));
}
The problem with all of that is that whenever Keycloak will trigger the refresh token, the token inside keycloak object is changed, the headers inside useActivities are changed BUT if I print the headers inside my getActivitiesList (// Note 2), or even inside the query function (// Note 1), headers will not be updated. Sometimes it just causes to make two requests (one that fails and show error, the other one actually working), some other times the app crashes without any explain. This makes me wonder why the query function will not update its headers and passed the "old" headers inside getActivitiesList.
For now we are mitigating this problem in two different points.
After keycloak init, we pass immediatly to axios a global header with axios.defaults.headers.common.Realm = KEYCLOAK_REALM;
After receiving a valid token from Keycloak, we overwrite the Authorization header with a new one: axios.defaults.headers.common.Authorization = 'Bearer ${keycloak?.token}';
This is not a perfect solution and we are here to search some info about this problem.
Someone get something similar? How to manage the token refresh in useQuery function?

Next.js cookies aren't coming through on router middleware

I'm attempting to create some route guarding using the new Next.Js 12 middleware feature. My authentication is based on a JWT token set on a cookie. I had previously implemented this using the API backend on Next.Js with no issues, and still when hitting the API routes the cookie will persist on the request no problem.
My issue appears when it will request a static page from the server. No cookies are attached so I can not determine if a User is authenticated and always redirect to a log in page. So for example the request to http://localhost:3000/ (Homepage) will not send any cookies to the middleware. But, http://localhost:3000/api/user will send a cookie to the middleware. Is there a setting I have missed in the documentation to allow this to happen?
Not sure if at all helpful but here is my _middleware.ts file that sits on the root of the pages.
import type { NextFetchEvent, NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
const middleware = (req: NextRequest, ev: NextFetchEvent) => {
console.log(req.cookies);
console.log(req.cookies['user']);
console.log(req.nextUrl.pathname);
if (req.nextUrl.pathname === '/') {
return NextResponse.redirect('http://localhost:3000/login');
}
};
export default middleware;
Next.js > 12.2
req.cookies.get("user")
Before Next.js 12.2,
req.cookies?.user
I had a same problem. I use tag for routing and it works but im not sure that it is a good choice.

In VueJS, how to access object returned by external api

I have added the hcaptcha widget to my login component using this package: https://github.com/hCaptcha/vue-hcaptcha. The challenge works as expected on the front end.
The response object as viewed in the network tab includes a token and looks like this:
expiration: 120
generated_pass_UUID: "P0_eyJ0eXAiOiJKV1QiLCJhbG...O9U"
pass: true
My question is how to pass that token with my email and password when I submit the login form.
Normally, I am using axios to make an explicit api call and I can define a variable like:
let response = axios.get('/whater_api')
and then use response.data to access whatever comes back. But I can't see how to do that here.
Have you tried the #verify="onVerify" event? it seems the result is emitted on that event, try to add methods onVerify on your vue instance like below:
methods: {
onVerify: function(e) {
console.log(e);
}
}
if it does return the response, you can make an object for the token, your email and password and the rest is just as usual.

Using Cypress to Test an App That Relies on OAuth

I've inherited a Node.js web app that uses relies on OAuth. Whenever you visit a page the app ensures you've authenticated. Please note, there no Angular, React, Vue, etc here. Each page is straight up HTML.
I want to test this site using Cypress. My problem is, I'm stuck on the initial redirect from the auth provider. Cypress acknowledge OAuth is a challenge.
commands.js
Cypress.Commands.add('login', (credentials) => {
var settings = {
'clientId':'<id>',
'scope':'<scope-list>',
...
};
var body = `client_id=${settings.clientId}&scope=${settings.scope}...`;
var requestOptions = {
method: 'POST',
url: 'https://login.microsoftonline.com/...',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body
}
cy.request(requestOptions);
});
Then, in my test, I have:
context('Home', () => {
it('Visits Successfully', () => {
cy.login();
cy.title().should('include', 'welcome');
});
});
In the test runner, I see the login POST request is occurring. I confirmed that an access token is being received using a console.log, however, my title is empty. It's like the redirect after OAuth isn't happening in Cypress. However, when I visit the site in the browser, the redirect is happening as expected.
What am I missing?
What you might be missing is confusing between the actual UI flow and the programmatic flow of doing OAuth with a 3rd party website.
What you would want to do is to complete the programmatic login and then send the required parameters to your OAuth callback URL for your app manually in the test code.
an example is given here (though it uses a different grant type it gives you an idea) https://auth0.com/blog/end-to-end-testing-with-cypress-and-auth0/#Writing-tests-using-Cypress-Login-Command
another issue on the cypress github that deals with a similar problem
https://github.com/cypress-io/cypress/issues/2085
this also might help:
https://github.com/cypress-io/cypress-example-recipes/blob/master/examples/logging-in__single-sign-on/cypress/integration/logging-in-single-sign-on-spec.js

Initial authentication check in ReactJS and Redux

Background: I have an app that is showing a list of movies, but what I want to do is to show the list only for users who are authorized (by checking token stored on the local-storage).
so the flow I want to achieve is:
user enters the app main page
check if has token in local storage
if yes check if it is authorized
if authorized = show list, else don't show
so what I do right now is in my main (wrapper) component right after I create my store:
const store = configureStore();
var token = localStorage.get(authConstants.LOCAL_STORAGE_TOKEN_KEY);
if(token){
store.dispatch(actions.checkInitialAuth(token));
}
checkInitialAuth actions is:
export function checkInitialAuth(token){
return dispatch => {
dispatch(requestLogin());
return fetch(authConstants.API_USER_DETAILS, {headers: { 'Authorization' : `Bearer ${token}`}})
.then(function(response){
if(!response.ok){
throw Error(response.statusText);
}
return response.json();
})
.then(function(user){
localStorage.set(authConstants.LOCAL_STORAGE_TOKEN_KEY, token);
dispatch(receiveLogin(user)); // <==========
dispatch(setTopMovies()); // <==========
})
.catch(function(err){
// TODO: handle errors
console.log(err);
});
}
}
so the question is, is it the right place to invoke the initial auth check right after the creating store and right before the element creation?
and now if I have to invoke more actions only if the user is authorized do I have to invoke them in the then inside the checkInitialAuth action? is it the right place to make all the action dispatch calls?
and last one, when the auth is wrong (I changed manually the token to be wrong on the local storage) the console.log(err) is logging as expected but I have also this annoying 401 error in the console, can I somehow avoid it?
thanks a lot!
is it the right place to invoke the initial auth check right after the creating store and right before the element creation?
Yes. Usually this is where all the initialization happens before store is passed to Provider.
is it the right place to make all the action dispatch calls?
This depends a lot on your application logic. You component can check if a user is authenticated itself to display the correct content for 'topMovies'. But nothing stops you from dispatch more actions here.
but I have also this annoying 401 error in the console, can I somehow avoid it?
It is the network request error. It is the response from the server your fecth is contacting. You can hide the error by change your Chrome Dev console filter if you really want to hide them (but why?).