next-auth pass the data in signin callback - next-auth

I am making login process with next-auth.
I am using Google as OAuth Provider.
// pages/api/auth/[...nextauth].ts
export default async function auth(req: any, res: any) {
return await NextAuth(req, res, {
//...
callbacks: {
async signIn({ user, account }) {
// console.log(user); // data exists.
const isUser = await apiForIsUser();
if(isUser) return true; // redirect to root page.
return '/sign-up'; // redriect to sign-up page.
}
}
});
}
above code works, but I can not touch data from OAuthProvider in sign-up page.
How can I pass the data from 'OAuthProvidertosign-up` page?

Related

How to implement Authentication using Riverpod in Flutter?

I have three providers for login => email, password, login.
then I am refreshing login provider which is a future provider and will call the login API.
now I need to see if the provider returns success then I will need to navigate to next page.
But .when() is not waiting for the refreshing to finish. Its logging "loading..." in the console.
`
ref.watch(email.notifier).state =
emails.trim().toLowerCase();
ref.watch(password.notifier).state = passwords;
final loginstate = ref.refresh(login);
loginstate.when(data: ((data) {
// log(data + "here");
if (data == "Success") {
context.go('/home');
}
}), error: (error, stackTrace) {
// log(error.toString() + "here");
}, loading: () {
log("loading....");
});
`
I need to Navigate to the Home page upon successful API call.

nextauth v4 credentials provider, adding the raw token to the session

I am new to nextauth credentials provider, and I have been following different tutorials on youtube and searching for answers here.
I have a web application using next.js and in it I have a bunch of rest apis to get data from mongodb. I have secured the api by accessing the token. I have used Postman to test the apis, and they work when I pass the raw token to in the Authorization header.
I need to get the raw token into the session object for the session call back in next-auth, so I then can call the apis from client side pages.
Any help would be appreciated.
In [...nextauth].js:
export default NextAuth({
providers: [
// Google Provider
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET
}),
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET
}),
CredentialsProvider({
id: "credentials",
name: "Credentials",
async authorize(credentials, req) {
console.log("In Authorization");
connectMongo().catch((error) => {
error: "Connection Failed...!";
});
// check user existance
const user = await Users.findOne({ email: credentials.email });
if (!user) {
throw new Error("No user found with this email");
}
// compare()
const checkPassword = await compare(
credentials.password,
user.password
);
// incorrect password
if (!checkPassword || user.email !== credentials.email) {
throw new Error("Email or Password don't match");
}
// check if user is enabled
if (user.active === AccountStatus.DISABLED) {
throw new Error(
"Account has been disabled. Please contact support to re-enable your account"
);
}
// Value returned will go into token property
//console.log("Returnng User Object", user);
return user;
}
})
],
session: {
strategy: "jwt",
maxAge: 60 * 60 * 24
},
callbacks: {
async jwt({ token, user, account, profile, isNewUser }) {
if (user) token.user = user;
if (account) token.accessToken = account.access_token;
return token;
},
async session({ session, token, user, account }) {
// Send properties to the client, like an access_token from a provider.
const { password, ...tokenPwdRemoved } = token.user;
session.user = tokenPwdRemoved;
return session;
}
},
pages: {
signIn: "/login"
}
});
Take a look at the Session callback:
callbacks: {
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.
session.accessToken = token.accessToken
return session
}
}
Keep in mind security concerns relating to the token and session.
Session callback
The session callback is called whenever a session is checked. By
default, only a subset of the token is returned for increased
security. If you want to make something available you added to the
token through the jwt() callback, you have to explicitly forward it
here to make it available to the client.

How to get data from next auth signIn Google provider in custom signIn page?

I need to get the data from the custom signIn page in order to write a user to the sanity database. But these signIn data is only obtained in [...nextauth].js file.
Code:
[...nextauth].js
import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
export default NextAuth({
// Configure one or more authentication providers
providers: [
GoogleProvider({
clientId: "xxxxxx",
clientSecret: "xxxxx",
}),
// ...add more providers here
],
secret: "something",
pages: {
signIn: '/auth/signin',
},
callbacks: {
async session({ session, token, user }) {
session.user.username = session.user.name
.split(' ')
.join('')
.toLocaleLowerCase()
session.user.uid = token.sub
return session
},
},
})
And these session data can be used inside components using useSession from next-auth.
But while trying to get the data to my custom signIn page, session is undefined.
import { getProviders, signIn as signIntoProvider } from "next-auth/react";
import { sanityClient } from "../../sanity";
import { useSession } from 'next-auth/react';
function signIn({users}) {
const { data: session } = useSession()
const onSubmit = (data) => {
fetch("/api/createUser", {
method: "POST",
body: JSON.stringify(data),
})
.then((resp) => {
console.log(resp);
})
.catch((err) => {
console.log(err);
});
};
const checkIfUserThere = async () => {
let newUser = session.user.email;
for (const data of users) {
if (data.email === newUser) {
return true;
}
}
return false;
};
useEffect(() => {
(async () => {
const userExists = await checkIfUserThere();
if(userExists === false ){
onSubmit(session.user); //write to sanity database
}
})();
}, []);
return (
<>
<button
className="rounded-lg bg-blue-500 p-3 text-white"
onClick={() =>
signIntoProvider("google", { callbackUrl: "/" })
}
>
Sign in with Google
</button>
</>
);
}
The above code is for a custom signIn page.
What is expected :
Once the user clicks the sign-in with the Google button, the session data must be added to the sanity database. But in my case, session here is undefined.
A simple way to do this is to write the logic inside the [...nextAuth].js file.
To solve the task of popularizing a document in Sanity from a Google authentication, you must first establish a connection to your Sanity project. Note that this import comes from the 'npm i #sanity/client' package or 'yarn add #sanity/client' and is not a reference to the configuration located in the sanity.js file. To do this, you can import the #sanity/client library and set up a configuration to connect to your project:
import sanityClient from "#sanity/client";
const config = {
dataset: "DATASET_NAME",
projectId: "PROJECT_ID",
useCdn: 'CDN'
token: "YOUR_TOKEN_SANITY",
};
export const client = sanityClient(config);
After setting up authentication with Google, you must set up a callback to run every time a user authenticates. This callback should look in Sanity to see if the user already exists, and if not, create a new user document in Sanity with the authenticated user's information:
const populateSanityUser = async (user) => {
const sanityUser = await client.fetch(
`*[_type == "users" && email == "${user.email}"]{ //check if the email exists
email
}`
);
if (sanityUser.length > 0) { //if exists
return sanityUser;
} else { //if not, create a new user with Google user session data
try {
await client.create({
_type: "user",
name: user.name,
email: user.email,
urlImage: user.image,
... // another field in your document
});
return user;
} catch (error) {
return error;
}
}
};
export default NextAuth({
...authOptions,
callbacks: {
async signIn(user) {
const isAllowedToSignIn = true; //optional
if (isAllowedToSignIn) {
const sanityUser = await populateSanityUser(user.user);
return sanityUser;
} else {
return false;
}
},
},
});
Important: Make sure that when you pass the user coming from NextAuth callback function you use user.user, as it comes nested with more data.
More information about callbacks in NextAuth here: https://next-auth.js.org/configuration/callbacks

Flutter Session API Login

I am trying to log in with the help of API and after login wants to see dashboard.
but I am getting a message {status: error, message: Seller Not Logged In}
I tried creating a session of login but it didn't work.
Login Page
postMethod() async {
var api = Uri.parse("https://www.nearxt.com/index.php?route=api/userlogin");
Map mapeddate ={
'email':_email.text,
'password':_password.text,
};
final response= await post(api,body: mapeddate);
if(response.statusCode==200)
{
await FlutterSession().set('token',_email.text);
print("Session Created");
}
var res = json.decode(response.body);
print(res);
}
it gives the output: Session Created
{cust: Login Success, error_warning: , success: }
after this, on homepage, I am trying to access the products after the login
Future fetchSellerProduct() async {
FlutterSession().get('token');
var url = await http.post(Uri.parse(
"https://www.nearxt.com/index.php?route=api/purpletree_multivendor/api/sellerproduct"));
if(url.statusCode==200)
{
print(url.statusCode);
}
setState(() {
map = json.decode(url.body);
print(map);
});
}
Output: {status: error, message: Seller Not Logged In}

Using koa-jwt with koa-router

I am implementing the a Nextjs service with koa, koa-router and kow-jwt, but I'm confused with the routing setting with them.
My project have 2 pages, one is dashboard and the other is login. The dashboard need to pass the verification and the login not. If the auth failed, then redirect user to login page.
I've search on the Internet, and found some examples as following, none of them chain them together.
Nextjs custom server
kow-jwt
Please give me some advice to make them work well together.
const app = next({dev});
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = new koa();
const router = new koaRouter();
router.get('/login', async ctx => {
await app.render(ctx.req, ctx.res, '/login', ctx.query);
ctx.respond = false;
});
router.get('/dashboard',
jwt({
secret: config.graphqlSecret
}),
async ctx => {
await app.render(ctx.req, ctx.res, '/dashboard', ctx.query);
ctx.respond = false;
}
);
// what is the purpose of this route?
router.get('*', async ctx => {
await handle(ctx.req, ctx.res);
ctx.respond = false;
});
server.use(async (ctx, next) => {
try {
await next();
} catch (err) {
if (err.statusCode === 401) {
ctx.redirect('/login');
}
}
});
server.use(router.routes());
server.use(router.allowedMethods());
server.listen(3000);
});
with the code above, the behavior is
If I link to dashboard with and without jwt token, it always redirect to login page.
If I link to dashboard from menu (implement with <Link> in Nextjs), it shows the content of dashboard.
Thank you for your help.
You need to include the jwt part in your server.use, not within the router. Make two different routers, one with the open routes and one with the protected ones. Then set open routes, set jwt middleware and then set protected routes:
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare()
.then(() => {
const server = new Koa()
const router = new Router()
router.get('/login', async ctx => {
await app.render(ctx.req, ctx.res, '/login', ctx.query);
ctx.respond = false;
});
router.get('/dashboard', async ctx => {
await app.render(ctx.req, ctx.res, '/dashboard', ctx.query);
ctx.respond = false;
});
router.get('*', async ctx => {
await handle(ctx.req, ctx.res)
ctx.respond = false
})
// this will keep redirecting user to login until is logged in
// if you remove it, will get an auth error unless you go manually
// to the login path
server.use(async (ctx, next) => {
try {
await next();
} catch (err) {
if (err.statusCode === 401) {
ctx.redirect('/login');
}
}
});
// we need to do it this way because of the way nextjs works with '*' path
// Middleware below this line is only reached if JWT token is valid
server.use(jwt({ secret: 'shared-secret' }).unless({ path: [/^\/b/] }));
// specify in unless the unprotected path
server.use(jwt({secret: config.graphqlSecret}).unless({ path: [/^\/login/] })).use(router.allowedMethods());
// every route protected by default
server.use(router.routes())
server.listen(3000);
})