SvelteKit unable to set cookie - cookies

Using SvelteKit 1.0.0-next.571
My application has a login route with:
+page.server.ts => redirects to / if locals.user is set
+page.svelte => show login page
signin/+server.ts => Login and get a jwt from graphql app running on the same machine.
+server.ts:
[..]
let gqlResponse = await response.json();
if ( gqlResponse.errors ) {
console.log("ERRORS FROM GRAPHQL MIDDLEWARE:", gqlResponse.errors);
return json( { error: gqlResponse.errors, isException: true } );
}
if (gqlResponse.data.login.user && !gqlResponse.data.login.error) {
opts.cookies.set('jwt', gqlResponse.data.login.token, {
path: '/',
maxAge: SESSION_MAX_AGE
});
opts.setHeaders( { 'Access-Control-Allow-Credentials': 'true' } )
opts.setHeaders({ 'Content-Type': 'application/json' })
}
return json( gqlResponse.data.login );
and the login handler in +page.svelte :
[..]
const fetchOptions = {
method: 'POST',
//mode: 'no-cors',
//redirect: 'follow' as RequestRedirect,
body: JSON.stringify(credentials),
credentials: 'include' as RequestCredentials
}
try {
const response = await fetch('/login/signin', fetchOptions);
const login = await response.json();
if (login.error) {
handleError(login);
return false;
}
} catch (e) {
return handleException(e);
}
goto('/', { replaceState: true, invalidateAll: true} );
This works fine in localhost, but connecting another device to the local network does not set any cookies making impossible to login:
Local: http://localhost:5173/
➜ Network: http://192.168.x.x:5173/
I also tried with different fetch options and cookie settings like:
opts.cookies.set('jwt', gqlResponse.data.login.token, {
path: '/',
httpOnly: true,
sameSite: 'strict',
// secure: true
maxAge: SESSION_MAX_AGE
});
but no luck, and now 'm stuck.

Related

AWS cognito not storing cookies in prod

Context:
I am using the amazon-cognito-identity-js SDK for authentication, as I am not using amplify for this project, only need to use cognito services. So far locally, I can do pretty much every fine, tokens come back and using the new AmazonCognitoIdentity.CookieStorage() it seems to be to store cookies locally using ({ domain: 'localhost', secure: 'false' }).
Also using nextjs v10.0.6
Problem
I tried to deploy the app to netlify and after installing it gives me back the tokens but does not store them in cookies on my browser.
Here is the snippet of code that I am using to sign in a user, there is a use case where the user was created by the admin, and will be forced to change password, thus the redirect to /changePassword
Any guidance would be amazing! My suspicion is that I am not configuring the domain right... but have tried every combination such as, removing the https, only including the autoGenerated subdomain part, etc
export const userPoolData = (): ICognitoUserPoolData => ({
UserPoolId: process.env.USER_POOL_ID || '',
ClientId: process.env.CLIENT_ID || '',
Storage: new CookieStorage({
domain: 'https://<autoGeneratedURL>.netlify.app',
secure: true,
expires: 10,
path: '/',
}),
});
const authenticationData = {
Username: username,
Password: password,
};
const authenticationDetails = new AuthenticationDetails(authenticationData);
const poolData = userPoolData();
const userPool = new CognitoUserPool(poolData);
console.log({ poolData });
const userData = {
Username: username,
Pool: userPool,
Storage: new CookieStorage({
domain: 'https://<autoGeneratedURL>.netlify.app',
secure: true,
expires: 10,
path: '/',
}),
};
const cognitoUser: CognitoUser = new CognitoUser(userData);
const userTokens: Pick<ResponseMessage, 'tokens'> = {};
console.log(authenticationData);
const authResponse = new Promise(() => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: (result) => {
console.log(result);
router.push({ pathname: '/' });
},
onFailure: (error) => {
console.log(error);
if (error.code !== 'InvalidParameterException' && error.code !== 'NotAuthorizedException') {
router.push({ pathname: '/changePassword', query: { username, password } });
}
},
});
});
try {
await authResponse;
} catch (error) {
return {
success: false,
code: 500,
error,
};
}
In case anyone runs into this, it turned out my suspicion was right and the fault was in the domain pattern, for a netlify app it should be configured as domain: <autoGeneratedURL>.netlify.app

Graphql Apollo setting cookies is dont working

I'm trying to set cookies in apollo client.
I'm setting the response cookie which works fine, also working on graphql playground with setting "request.credentials": "same-origin", or "include" and it stores cookies successfully.
My problem starts when I'm trying to store cookies from FE app (React, Apollo client). When i put the credentials: "same-origin" the app is working but the cookies are not saved. And when i use "include" the queries are cors blocked.
FRONTEND
const RouterComponent: FC = () => {
const cache = useMemo(() => {
return new InMemoryCache();
}, []);
const client = useMemo(() => {
const token = localStorage.getItem('token') || 'token';
const httpLink = createHttpLink({
uri: 'http://localhost:4000/graphql',
credentials: 'include',
headers: {
authorization: token ? `Bearer ${token}` : '',
},
});
const link = from([
httpLink,
createUploadLink({
uri: 'http://localhost:4000/graphql',
}),
]);
return new ApolloClient({
link,
cache,
typeDefs,
});
}, [cache]);
return (
<ApolloProvider client={client}>
<Switch>
<Route exact path="/" component={MainPage} />;
<Route exact path="/:category" component={Category} />;
</Switch>
</ApolloProvider>
);
};
QUERY
games: (_: any, args: any, {req, res}: any) => {
const refresh_token = sign({userId: "123"}, "secret", {expiresIn: "7d"})
const access_token = sign({userId: "123"}, "secret", {expiresIn: "15min"})
res.cookie('refresh-token', refresh_token, {expire: 60 * 60 * 24 * 7}) // 7 days
res.cookie('access-token', access_token, {expire: 60 * 15}) // 15 mins
return Game.find()
}
SERVER.TS
const { ApolloServer } = require( 'apollo-server-express');
const {typeDefs} = require( './typeDefs');
const {resolvers} = require( './resolvers');
const express = require( 'express');
const cors = require( 'cors');
const path = require( 'path');
const bodyParser = require( 'body-parser');
const mongoose = require("mongoose");
const dotenv = require('dotenv');
const MONGO_CONNECTION = ""
const app = express();
export default (async function () {
try {
await mongoose.connect(MONGO_CONNECTION, {
useNewUrlParser: true,
useUnifiedTopology: true})
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req, res }: any) => {
return {
req,
res
};
},
});
const corsConfig = {
origin: '*',
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
};
dotenv.config();
app.use(function (req: any, res: any, next: any) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/images', express.static(path.join(__dirname, 'images')));
const dir = path.join(process.cwd(), 'images');
app.use(express.static(dir));
app.use(express.static('public'))
app.use(express.static('files'))
server.applyMiddleware({ app, cors: corsConfig });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
)
} catch (err) {
console.error(err);
}
})();
thank you for any help

Set Session ID Cookie in Nuxt Auth

I have the following set up in my nuxt.config.js file:
auth: {
redirect: {
login: '/accounts/login',
logout: '/',
callback: '/accounts/login',
home: '/'
},
strategies: {
local: {
endpoints: {
login: { url: 'http://localhost:8000/api/login2/', method: 'post' },
user: {url: 'http://localhost:8000/api/user/', method: 'get', propertyName: 'user' },
tokenRequired: false,
tokenType: false
}
}
},
localStorage: false,
cookie: true
},
I am using django sessions for my authentication backend, which means that upon a successful login, i will have received a session-id in my response cookie. When i authenticate with nuxt however, i see the cookie in the response, but the cookie is not saved to be used in further requests. Any idea what else i need to be doing?
This is how I handled this, which came from a forum post that I cannot find since. First get rid of nuxt/auth and roll your own with vuex store. You will want two middleware, one to apply to pages you want auth on, and another for the opposite.
This assumes you have a profile route and a login route that returns a user json on successful login.
I'm also writing the user to a cookie called authUser, but that was just for debugging and can be removed if you don't need it.
store/index
import state from "./state";
import * as actions from "./actions";
import * as mutations from "./mutations";
import * as getters from "./getters";
export default {
state,
getters,
mutations,
actions,
modules: {},
};
store/state
export default () => ({
user: null,
isAuthenticated: false,
});
store/actions
export async function nuxtServerInit({ commit }, { _req, res }) {
await this.$axios
.$get("/api/users/profile")
.then((response) => {
commit("setUser", response);
commit("setAuthenticated", true);
})
.catch((error) => {
commit("setErrors", [error]); // not covered in this demo
commit("setUser", null);
commit("setAuthenticated", false);
res.setHeader("Set-Cookie", [
`session=false; expires=Thu, 01 Jan 1970 00:00:00 GMT`,
`authUser=false; expires=Thu, 01 Jan 1970 00:00:00 GMT`,
]);
});
}
store/mutations
export const setUser = (state, payload) => (state.user = payload);
export const setAuthenticated = (state, payload) =>
(state.isAuthenticated = payload);
store/getters
export const getUser = (state) => state.user;
export const isAuthenticated = (state) => state.isAuthenticated;
middleware/redirectIfNoUser
export default function ({ app, redirect, _route, _req }) {
if (!app.store.state.user || !app.store.state.isAuthenticated) {
return redirect("/auth/login");
}
}
middleware/redirectIfUser
export default function ({ app, redirect, _req }) {
if (app.store.state.user) {
if (app.store.state.user.roles.includes("customer")) {
return redirect({
name: "panel",
params: { username: app.store.state.user.username },
});
} else if (app.store.state.user.roles.includes("admin")) {
return redirect("/admin/dashboard");
} else {
return redirect({
name: "panel",
});
}
} else {
return redirect("/");
}
}
pages/login- login method
async userLogin() {
if (this.form.username !== "" && this.form.password !== "") {
await this.$axios
.post("/api/auth/login", this.form)
.then((response) => {
this.$store.commit("setUser", response.data);
this.$store.commit("setAuthenticated", true);
this.$cookies.set("authUser", JSON.stringify(response.data), {
maxAge: 60 * 60 * 24 * 7,
});
if (this.$route.query.redirect) {
this.$router.push(this.$route.query.redirect);
}
this.$router.push("/panel");
})
.catch((e) => {
this.$toast
.error("Error logging in", { icon: "error" })
.goAway(800);
The cookie is sent by the server but the client won't read it, until you set the property withCredentials in your client request (about withCredentials read here)
To fix your problem you have to extend your auth config with withCredentials property.
endpoints: {
login: {
url: 'http://localhost:8000/api/login2/',
method: 'post'
withCredentials: true
}
}
Also don't forget to set CORS policies on your server as well to support cookie exchange
Example from ExpressJS
app.use(cors({ credentials: true, origin: "http://localhost:8000" }))
More information about this issue on auth-module github

hapi-auth-cookie not setting cookie immediately after redirect with bell

I'm using Bell for Meetup OAuth, then persisting with hapi-auth-cookie.
Here are the relevant parts of code.
server.auth.strategy('session', 'cookie', {
cookie: 'sessionid',
password: '32_char_password',
// redirectTo: '/login', //this causes a loop immediately after allowing access
redirectTo: false,
isSecure: false,
});
server.auth.strategy('meetupauth', 'bell', {
provider: 'meetup',
password: '32_char_password',
isSecure: false,
providerParams: {
set_mobile: 'on'
},
clientId: 'client_id',
clientSecret: 'client_secret',
});
server.route({
method: ['GET'],
path: '/login',
config: {
auth: 'meetupauth',
handler: (request, reply) => {
request.cookieAuth.set({
sid: request.auth.credentials.profile
});
return reply.redirect('/user');
}
}
});
server.route({
method: 'GET',
path: '/user',
config: {
auth: 'session',
handler: (request, reply) => reply('My Account'),
}
});
The code works fine, except immediately after allowing access to Meetup. Once allowed access, the /login page redirects to /user. Not redirecting back to the login page, I get a 401, and after I reload /user the cookie is there. Once I've given access, it works fine; just the initial allow. What is happening?
Try setting the "isSameSite" variable to the "Lax" value
const options = {
connections: {
state: {
isSameSite: 'Lax'
}
}
};
const server = new Server(options);

Trying to get then send a cookie using react and fetch

I've been trying to implement some authentication component in my app for a few hours now, and I still don't understand some of the things that are happening.
Basically, I'd like to send a POST request containing some credentials to my API, which sends me a cookie back with a token if the credentials worked. Then, the cookie should be included in the headers of all future requests to my API (which I believed was automatic).
server.js (my API is a mockup for now, with JSON files)
...
app.post('/api/login', jsonParser, (req, res) => {
fs.readFile(ACCOUNTS_FILE, (err, data) => {
if (err) {
console.error(err);
process.exit(1);
}
const accounts = JSON.parse(data);
const credentials = {
email: req.body.email,
password: req.body.password,
};
var token = null;
for (var i = 0; i < accounts.length; ++i) {
const account = accounts[i];
if (account.email === credentials.email
&& account.password === credentials.password) {
token = account.token;
break;
}
}
if (token) {
res.setHeader('Set-Cookie', `access_token=${token}; Secure; HttpOnly;`);
res.json({ token });
} else {
res.json({ token: null });
}
});
});
...
app.js
...
handleConnection(e) {
e.preventDefault();
const email = this.state.email.trim();
const password = this.state.password.trim();
if (!email && !password) {
return (false);
}
fetch(loginUrl, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
credentials: 'include',
},
body: JSON.stringify(this.state),
})
.then((response) => response.json())
.then((data) => {
console.log(data);
})
.catch((error) => {
console.warn(error);
});
return (true);
}
...
Now the console.log(data) always displays my token (or null if my credentials are wrong), but the cookie thing doesn't work...
See, I receive the Set-Cookie header, but I still have no cookie on my page.
And even if I managed to get the cookie, when I try to create a cookie using document.cookie = "access_token=123"; and then send the request again, my cookie doesn't go in my header like it would with a jQuery Ajaxcall :
I read here that adding credentials: 'include' would save the day, but unfortunately it didn't.
What am I missing here?
Thanks in advance!
I had the same problem and I found the answer in Peter Bengtsson's comment here: https://davidwalsh.name/fetch
If I understood, in your case the fetch should be:
fetch(loginUrl, {
credentials: 'same-origin',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(this.state),
})