Cypress OKTA Authenticate user with email MFA via API - javascript

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.
});
})

Related

RTK Query set token inside cookies but it is not having any effect

I started learning RTK Query few days ago and I have been enjoying it cool features and simplicity, so I decided to switch from useContext to RTK Query in the project I'm building with Next.js and a custom server using Node.js and express. In this project, I made an api route for login and signup which would be hit by using RTK Query and Axios with the help of custom axios base query RTK Query provided. The login and signup api endpoints already had a logic to store token inside the cookies storage. I use RTK Query with axios to post user request so they can get a response of their token store in cookies storage. This logic of storing user token in the cookies works well with useContext and axios.
But the logic didnot work as expected while using RTK Query, and these are results:
The token was set in the cookies storage but I get a response status of 401.
When user submit their credentials in the login or signup page, they are supposed to be redirected to profile page with their details being display since I made use of useQuery to fetch user profile. But the data did not display. Which means the token stored is not effective.
I'm unable to get the user information even though the token had been stored in the cookies.
Whenever I click on a link to redirect me to a particular route, useQuery didnot fetch anything and when I go back to profile, the user details will be fetched and display but when I refresh the page again, no data will be dsiplay
Whenever a get request was successful at the first time, I alway lose the data whenever I refresh the page.
All these issues only happens to routes that are protected with middleware in the backend and the middleware is to verify the token. But I have no issue with reloading a page which data that is not protected in the backend.
I also have a middleware in my backend for verifying and checking if token is true in the cookie to check if user is authenticated, if it is false, user should be directed to the login page in the frontend. The logic for fetching and check if data is true is inside HOC component which was wrapped with protected route, but whenever the data value is false, am still able to go to any route in the frontend instead of redirecting me to login page. And when I log the data to the console I recieve the correct data.
Removing token from cookie works successfully.
export const fetcherApi = createApi({
reducerPath: "fetcherApi",
baseQuery: axiosBaseQuery({
baseUrl: "http://localhost:5000/",
}),
tagTypes: ["User"],
endpoints(build) {
return {
//________Authentication
registerUser: build.mutation({
query: (form) => ({
url: "register",
method: "post",
data: form,
}),
invalidatesTags: ["User"],
}),
loginUser: build.mutation({
query: (form) => ({
url: "login",
method: "post",
data: form,
}),
invalidatesTags: ["User"],
}),
getAuth: build.query({
query: () => ({ url: "auth", method: "get" }),
}),
//__________User
updateUserName: build.mutation({
query: (...rest) => ({
url: "update-user",
method: "put",
data: rest,
}),
invalidatesTags: ["User"],
}),
getUser: build.query({
query: () => ({ url: "user", method: "get" }),
providesTags: ["User"],
}),
//__________Profile
postProfile: build.mutation({
query: (form) => ({
url: "login",
method: "post",
data: form,
}),
}),
getAllProfiles: build.query({
query: () => ({ url: "all-profiles", method: "get" }),
}),
getUserProfile: build.query({
query: () => ({ url: "profile/me", method: "get" }),
}),
//___________Car
postCar: build.mutation({
query: (form) => ({
url: "new-car",
method: "post",
data: form,
}),
}),
putCar: build.mutation({
query: ({ id, ...rest }) => ({
url: `update-car/{id}`,
method: "put",
data: { rest },
}),
}),
getAllCars: build.query({
query: () => ({ url: "all-cars", method: "get" }),
}),
getCarById: build.query({
query: (id) => ({ url: `onecar/${id}`, method: "get" }),
}),
getAllUserCars: build.query({
query: () => ({ url: "my-car", method: "get" }),
}),
};
},
});
export const {
// ______Authentication______
useGetAuthQuery,
useRegisterUserMutation,
useLoginUserMutation,
//_______User_________
useUpdateUserNameMutation,
useGetUserQuery,
//_____Profile_________
useGetUserProfileQuery,
useGetAllProfilesQuery,
usePostProfileMutation,
//_____Car____________
usePostCarMutation,
usePutCarMutation,
useGetAllCarsQuery,
useGetCarByIdQuery,
useGetAllUserCarsQuery,
} = fetcherApi;
I solve this issue by adding credentials: include as baseQuery parameter and I added async and await in my functions
baseQuery: fetchBaseQuery({
baseUrl: "https://my-app.herokuapp.com/",
credentials: "include",
}),

OAuth2.0 token post request is responding 401 (invalid_client)

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
}
})
}

NuxtJs login works but unauthorized 401

I am using NuxtJs auth module to handle my authorization in the state. For the auth I wrote an express api which works.
I have following configuration in my nuxt.config.js:
axios: {
baseURL: 'http://localhost:4000/api'
},
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/users/login', method: 'post', propertyName: 'data.token' },
user: { url: '/users/me', method: 'get', propertyName: 'data' },
},
}
}
},
And in my login component I call the login route like this:
const { data } = await this.$auth.loginWith('local', {
data: this.login
})
This call the /api/users/login route successfully (200) and after that calls the /api/users/me with an error saying
xhr.js:178 GET http://localhost:4000/api/users/me 401 (Unauthorized)
In postman I am calling the api route which returns the user like this*
> Get - localhost:4000/api/users/me
>
> Authorization:
>
> Type: Bearer Token Token: xxxx
Which returns the users data.
I read that nuxt auth module default the type to 'Bearer' but in my case it does not work.
The user login work but the second route which returns the user data does not work due to authorization. The Api is not inside the nuxtjs it is a different project written in Express.
You can try this:
axios: {
baseURL: 'http://localhost:4000/api' },
auth: {
strategies: {
local: {
endpoints: {
login: { url: '/users/login', method: 'post', propertyName: 'data.token' },
user: { url: '/users/me', method: 'get', propertyName: 'data' },
},
tokenType: ''
}
}
},
Setting tokenType to an empty string overrides the default "Bearer". Some server configurations may throw a 401.

How to automate the OAuth 2.0 token generation using Artillery?

I want to automate the OAuth 2.0 token automatically via javascript. Is there any way I can do that and obtain the token to use it in the artillery scrtips.
For the OAuth token generation I have below details:
Auth URL
Client ID
Scope
It is done by client authentication credentials.
Below is the sample code I am using to generate the token:
var ClientOAuth2 = require('client-oauth2')
var Auth = new ClientOAuth2({
clientId: 'ClientID',
accessTokenUri: 'https://Auth_URL/v2.0/token',
authorizationUri: 'https://Auth_URL/v2.0/authorize',
redirectUri: 'https://Auth_URL/',
scope: 'api://Scope/access_as_user'
})
Auth.owner.getToken('Username', 'password')
.then(async (user) => {
await console.log(user) //=> { accessToken: '...', tokenType: 'bearer', ... }
}).catch((e) => { console.log('error show',e); })
.finally( () => console.log('end'));
You can declare your custom JS files which will be triggered every time before the request:
Your YAML file can be like here:
config:
target: "https://baseUrl.com"
phases:
- duration: 60
arrivalRate: 100
processor: "./customFile.js"
scenarios:
- flow:
- post:
url: "/pathInYourApi"
headers:
Content-Type: "application/json"
Accept: application/json
json: {}
beforeRequest: "beforeRequest"
and then your customFile.js script:
module.exports = {
beforeRequest: beforeRequest,
};
function beforeRequest(requestParams, context, ee, next) {
// Call your OAuth client, and after you obtain token you can assign it to requestParams Authorization header
// eg. requestParams.headers.Authorization = `Bearer + ${token}`
return next(); // MUST be called for the scenario to continue
}

Can't set user session with Vue and Django

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.

Categories

Resources