Endpoint Basic Auth VueJs - http

I am trying to access an endpoint with username and password but the console give me a 401()
this is my code:
created () {
this.$http.get(URL, {
username: 'xxxxxxx',
password: 'xxxxx'
}).then(response => {
console.log(response)
})
}
Is it the correct way to access an endpoint with VueJS?

You have to provide the username and password codified in Base64.
const encodedUserPswd = btoa(`${user}:${pswd}`);
axios.get(URL, {}, {
headers: { `Authorization: Basic ${encodedUserPswd}` },
}).then((response) => {
// ...
});

Related

Next Auth Credentials Provider - SignIn() and Mapping to my API Dto

I am using Next.js and Next Auth to talk to my backend C# ASP.NET API.
My API's response is the following DTO:
{
"data": {
"accessToken": "string",
"refreshToken": "string",
"email": "user#example.com",
"username": "string",
"roles": [
"string"
]
},
"success": true,
"message": "string"
}
I am having a hard time getting that info into the next auth session so that I can grab it with useSession().
I'd also like to be able to display the API "message" to the user in the login form. Incase their account is locked or whatever.
This is what I have:
[...nextauth].js
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { API_URL } from "#/constants";
export const authOptions = {
// Configure one or more authentication providers
providers: [
// Add Your Providers Here
CredentialsProvider({
name: "Credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
const { usernme, password } = credentials;
const body = JSON.stringify({
username,
password,
});
// Login request to our API.
const res = await fetch(`${API_URL}/Login`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json; charset=utf-8",
},
body: body,
});
const data = await res.json();
// Our API's response contains
/*
{
"data": {
"accessToken": "string",
"refreshToken": "string",
"email": "user#example.com",
"username": "string",
"roles": [
"string"
]
},
"success": true,
"message": "string"
}
*/
const user = {
success: data.success,
message: data.message,
email: data.data.email,
username: data.data.username,
accessToken: data.data.accessToken,
refreshToken: data.data.refreshToken,
roles: data.data.roles,
};
// EVERYTHING TO HERE IS GOOD!
// I CAN GET THE user OBJECT FILLED.
if (res.ok && user) {
return user; //<---- is this actually returning the full user object to the session?
} else {
return null;
}
},
}),
],
pages: { signIn: "/login" },
};
export default NextAuth(authOptions);
Navbar Links:
<Nav.Link as={Link} href='/login' onClick={() => signIn()}>Login</Nav.Link>
<Nav.Link as={Link} href='/signout' onClick={() => signOut({callbackUrl: '/'})}>Signout</Nav.Link>
Login form:
// Get data from the form.
const nextAuthSettings = {
username: event.target.username.value,
password: event.target.password.value,
redirect: true,
callbackUrl: "/dashboard",
};
// Send the form data to Next Auth
const result = await signIn("credentials", nextAuthSettings);
// Error Handling
// THIS DOES NOT WORK
// I don't think signIn() returns a copy of the user object unfortunately...
if (!result.success) {
// Display the API Error Message On The Page
setErrorMsg(result.message);
}
And then in various pages, when I want to access the user object I am doing this :
import { useSession } from "next-auth/react";
const { data: session } = useSession();
// This only shows the email
<span>{session?.user.email}</span>;
// It looks like a JWT or something when I console log it
{
"user": {
"email": "users#email.com"
},
"expires": "2023-03-16T12:39:28.120Z"
}
Any help appreciated!
I need to be able to access the user object my API is returning throughout my app.
At the moment I'm just getting this session.user.email and nothing else ??
it's like I am not mapping the API's response to whatever Next Auth wants me to create...
you have to use callbacks :
callbacks: {
async jwt({ user, token }) {
// update token from user
if (user) {
token.user = user;
}
// return final_token
return token;
},
async session({ session, token }) {
// update session from token
session.user = token.user;
return session;
},
},
Now you can access your session with useSession() and your token with getToken()

Retrieve wordpress REST current user in nextjs app

I'm using the JWT Authentication for WP-API plugin to generate the token.
User crendetials are submitted to /jwt-auth/v1/token endpoint then store token to cookie then setState as follow
setAuth({ status: 'SIGNED_IN', user: response.data.user_display_name});
then on restricted page I check if user is valid from getServerSideProps
export const authenticateUser = async (ctx) => {
try {
const response = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/wp/v2/users/me`, {}, {
headers: {
'Authorization': `Bearer ${token}`
}
});
// if is it returns the right informations
return { status: 'SIGNED_IN', user: response.data.user}
// else
return { status: 'SIGNED_OUT', user: null}
}
}
export const getServerSideProps = async context => {
// retrieve user
const auth = await authenticateUser(context);
console.log(auth);
// if there is no authenticated user, redirect to homepage
if (auth.status === 'SIGNED_OUT') {
return {
props: {},
redirect: { destination: "/" },
}
}
return { props: { user: auth.user } }
}
In postman the requests are working fine using the right authorization bearer token.
But in my nextjs app I have the following response
{
code: 'rest_not_logged_in',
message: 'Vous n’êtes actuellement pas connecté.',
data: { status: 401 }
}
I also tried to check if user id exists using
const response = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/wp/v2/users/${userId}`, {}, {
headers: {
'Authorization': `Bearer ${token}`
}
});
but I have the following response
{
code: 'rest_user_cannot_view',
message: 'Désolé, vous n’avez pas l’autorisation de lister les comptes.',
data: { status: 401 }
}
Any help will be appreciate.
EDIT
It appears that the problem come from axios, fetch API works great.

How to get accessToeken in NextAuth?

I am trying to implement a traditional authentication setup with NextAuth. The backend is sending a response like the below after a successful login. The library looks excellent but I don't see where the raw accessToken is saved or any way to get this. I need to add it with every request header I send to the backend. How to deal with this kind of authentication? I would be pleased if you spent some of your time helping me in this regard.
Backend Response after login. FYI I can change the response if need
{
"statusCode": 200,
"data": {
"accesstoken": "eyJhbGcicCI6IkpXVCJ9.eyJlbWFpbCI6ImFzaWY.......",
"user": {
"name": "Participant",
"image": "https://i.pravatar.cc/150?img=4",
"email": "asif.saho#gmail.com"
}
}
}
This is what my [...nextauth].ts looks like.
import axios from 'axios';
import NextAuth, { Session, User } from 'next-auth';
import { JWT } from 'next-auth/jwt';
import CredentialsProvider from 'next-auth/providers/credentials';
import { AUTH_CONST } from '../../../constants/authConst';
import { log } from '../../../services/logger';
const providers = [
CredentialsProvider({
type: 'credentials',
id: 'credentials',
name: 'credentials',
credentials: {
email: { label: 'email', type: 'email' },
password: { label: 'password', type: 'password' },
},
authorize: async (_credentials, req) => {
const res: Response = await axios.post(AUTH_CONST.signInBeUrl, {
email: req.query!.email,
password: req.query!.password,
});
if (res.data.statusCode === 200) {
return res.data.data.user;
}
return null;
},
}),
];
const logger = {
error(code: any, metadata: any) {
log.error('next auth', JSON.stringify(code, null, 2));
log.error('next auth', JSON.stringify(metadata, null, 2));
},
warn(code: any) {
log.warn('next auth', JSON.stringify(code, null, 2));
},
debug(code: any, metadata: any) {
log.info('next auth', JSON.stringify({ code, metadata }, null, 2));
},
};
export default NextAuth({
secret: process.env.SECRET,
providers,
debug: process.env.AUTH_DEBUG === 'true',
logger,
pages: {
signIn: AUTH_CONST.signIn,
signOut: AUTH_CONST.signOut,
error: AUTH_CONST.error,
},
});
With NextAuth, you can use the session strategy as jwt. This is the default. The session is saved in a cookie and never persisted anywhere.
session: {
strategy: "jwt"
}
You can add an API handler that accepts the token and sets it to the cookie.
For example
export default function handler(req, res) {
const { token } = req.body;
res.setHeader('Set-Cookie', `token=${token}`);
res.json({});
}
The cookie is attached to all the requests sent to your backend.
// This is an example of how to read a JSON Web Token from an API route
import { getToken } from "next-auth/jwt"
export default async (req, res) => {
const token = await getToken({ req })
if (token) {
// Signed in
console.log("JSON Web Token", JSON.stringify(token, null, 2))
} else {
// Not Signed in
res.status(401)
}
res.end()
}
Example is taken from the NextAuth doc.

How to get logged user in vuejs

I made a jwt authetication using asp.net core and vuejs
this is my auth controller :
[Route("Login")]
[HttpPost]
public IActionResult Login(LoginArgument loginArgument)
{
var user = _userService.GetByEmail(loginArgument.Email);
if (user == null) return BadRequest(error: new { message = "Invalid credential : verify email" });
if (!BC.BCrypt.Verify(text: loginArgument.Password, hash: user.Password))
{
return BadRequest(error: new { message = "Invalid credential : verify password" });
}
var jwt= _jwtService.Generate(user.Id);
Response.Cookies.Append(key: "jwt", value: jwt, new Microsoft.AspNetCore.Http.CookieOptions
{
HttpOnly=false,
SameSite=Microsoft.AspNetCore.Http.SameSiteMode.None
}) ;
return Ok(user);
}
[Route("User")]
[HttpGet]
public IActionResult User()
{
try
{
var jwt = Request.Cookies["jwt"];
var token = _jwtService.Verify(jwt);
int userId = int.Parse(token.Issuer);
var user = _userService.GetById(userId);
return Ok(user);
}
catch (Exception)
{
return Unauthorized();
}
}
and this is the login in vue
<script lang="ts">
import { reactive } from 'vue';
import { useRouter } from "vue-router";
export default {
name: "Login",
setup() {
const data = reactive({
email: '',
password: ''
});
const router = useRouter();
const submit = async () => {
await fetch('https://localhost:44391/api/Auth/Login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify(data)
});
await router.push('/Countries');
}
return {
data,
submit
}
},
}
the login part is working in front and back sides perfectly and i can see the cookies
the problem is when i try to get the logged user. in back side i can get it successfully but in front it says that no user is logged
here is the loggedUser vue
<script lang="ts">
import { onMounted, ref } from 'vue';
export default {
name: "LoggedUser",
setup() {
const message = ref('You are not logged in!');
onMounted(async () => {
const response = await fetch('https://localhost:44391/api/Auth/User', {
headers: { 'Content-Type': 'application/json' },
credentials: 'include'
});
const content = await response.json();
message.value = `hi ${content.name}`;
});
return {
message
}
}
}
Here is the errors i got when i inspect the page :
this issues appear the moment of login
1- Mark cross-site cookies as Secure to allow setting them in cross-site contexts
2- Migrate entirely to HTTPS to have cookies sent to same-site subresources
this one appears when i call loggedUser in front even so it works in the back side
{type: "https://tools.ietf.org/html/rfc7235#section-3.1", title: "Unauthorized", status:
401,…}
status: 401
title: "Unauthorized"
traceId: "00-b4a9f6fee8dff6439952ded0bb50005d-43c9aee84c454b40-00"
type: "https://tools.ietf.org/html/rfc7235#section-3.1"
You need to send the access token in the request headers
Example:
let token = '???'
const response = await post('localhost/api/auth/user', {
headers: {
'Content-Type': 'application/json'
'Authorization' : 'Bearer '+ token
}
});

How to get, store and reuse firebase token in cypress api automated testing

after sending in body "email" and "password" https://identitytoolkit.googleapis.com/ returns a few objects in the response.
One of them is "idToken": with a value of the token.
What do I need?
I need to get this token, store it in variable and reuse it in further tests.
So far I prepared something like this:
it("Get a fresh admin firebase token", () => {
cy.request({
method: "POST",
url: "https://identitytoolkit.googleapis.com/...",
body: {
"email": "myUsername",
"password": "myPassword",
"returnSecureToken": true
},
headers: {
accept: "application/json"
}
}).then((responseToLog) => {
cy.log(JSON.stringify(responseToLog.body))
}).then(($response) => {
expect($response.status).to.eq(200);
})
})
})```
Above code works, but cy.log() returns the whole body response. How can I separate only idToken and reuse it in my next API scenarios?
Considering that idToken in in response body so inside then() you can directly wrap the value and save it using an alias and then use it later.
it('Get a fresh admin firebase token', () => {
cy.request({
method: 'POST',
url: 'https://identitytoolkit.googleapis.com/...',
body: {
email: 'myUsername',
password: 'myPassword',
returnSecureToken: true,
},
headers: {
accept: 'application/json',
},
}).then((response) => {
cy.wrap(response.body.idToken).as('token')
})
})
cy.get('#token').then((token) => {
cy.log(token) //logs token or Do anything with token here
})
In case you want to use the token in a different it block you can:
describe('Test Suite', () => {
var token
it('Get a fresh admin firebase token', () => {
cy.request({
method: 'POST',
url: 'https://identitytoolkit.googleapis.com/...',
body: {
email: 'myUsername',
password: 'myPassword',
returnSecureToken: true,
},
headers: {
accept: 'application/json',
},
}).then((response) => {
token = response.body.idToken
})
})
it('Use the token here', () => {
cy.log(token) //prints token
//use token here
})
})

Resources