Closed trulymittal closed 3 years ago
Hi there! So I'm not sure if I understand, but you would like to sign in to a native mobile app with next-auth?
I'm not entirely sure if it's possible. At the very least you will need a web app, as the signin page will send you html if you do a GET request, or will check for cookies if you send a POST request. I'm not aware that cookies are a thing outside of web apps, but please do link me to some sources if I'm wrong.
Or maybe even your mobile app, to get a picture of how you would integrate.
Yes, I want to sign-in using a native mobile app, to utilize the full power of Nextjs, since it has API routes also.
Secondly, we can handle cookies on mobile apps, but that comes with a lot of overhead so therefore we use jwt tokens, which by far is easy to implement.
Let me explain, what I am trying to ask or may a feature request!
Suppose I have made an app using NextJs, we can include both server and client (web) code in one application and use next-auth
and we're good to go. The same can be done with firebase or with any other auth provider.
Now my web application is doing good and now I want to roll out native mobile apps, then how I am supposed to integrate next-auth
with them? maybe a proposed solution that next-auth
API auth routes like sign-in should provide a way to send back access tokens or some kind of token that can be used later by a mobile app to authenticate itself against Nextjs app. This kind of thing works with firebase, auth0 or other auth providers since I can get tokens either I am on the web or on native mobile.
I like the simplicity of next-auth
and the very idea that I own my data.
One thing more I cannot find the use of next-auth
on HTTP GET routes, since Nextjs suggests to NOT query the API routes from within the application but instead use getServerSideProps or getStaticProps to get the data from DB directly.
From Next docs:
Note: You should not use fetch() to call an API route in getStaticProps. Instead, directly import the logic used inside your API route. You may need to slightly refactor your code for this approach.
Fetching from an external API is fine!
Any updates on this?
still wondering for any help regarding this issue??
yeah, looking into the code, the real issue is that is thought just for web-app, and not as micro-service-oriented. Next-auth should be able to send JSON-only on request, like the response of csrfToken, instead of embedding web-flow logic in the routes (I like the code, but this is really an anti-pattern consider Next is a serverless platform) Solution one is you can create your own REST API using the library, which is really good, and reply just JSON for every route. Solution two is to have the extend index.js to reply also to add some other extra switches if the request requires a JSON response. But Next-auth is definitively not thought for rest API remote authentication, and it is a pity because it is the real killer application for Next. Solution 3 is to build those features with passports.js and connect-next.js. More works to do, utterly old-style - but you have full control and a solid-production-ready solution. It is a pity - REST authentication is a KILLER feature for Nextjs to use the scaling power of Lambdas // Vercel, have it into the next-auth library would determine the success. Most of the companies have an app, and there must be just one identity management system shared across devices.
Hi there! It looks like this issue hasn't had any activity for a while. It will be closed if no further activity occurs. If you think your issue is still relevant, feel free to comment on it to keep it open. (Read more at #912) Thanks!
Maybe then I would never use next-auth for authentication ever, it defeats the purpose of API routes. Better would be to code auth on own, else the application will be bottlenecked only to web-app.
I think there really should be a way to allow authentication from a mobile app (through REST endpoints with JSON response).
This would allow to completely reuse on a mobile app (and why not, from a create-react-app based app) all the server side implementation of a web app;
It's quite common the need of a web and mobile app based on the same backend, but in this way the authentication logics are not reusable at all
I'm glad that people are interested in this, but currently I don't have the bandwidth to think about this. Instead of telling how awesome it would be, I would appreciate if we converge to meaningful discussion here, maybe someone who needs this functionality could look at the source code to come up with ideas? It's all available.
FWIW, I do think we should refractor the core in a way that #1535 could be resolved.
I don't know if that would help here though. Basically handlers would return objects like:
interface HandlerResponse {
headers: Headers,
cookies: Record<string, {
value: string
expires: Date
//...
}
body: JSON
}
and all header and cookie setting (so the WEB stuff?) would be contained within a single file (server/index.js
).
This might also be useful if we want to expand to other frameworks (see #2294)
Is there any update on this? I’m facing the exact same problem. I have a next app with authentification made by nextauth.
Now I want to create a flutter app an fetch my nexts api routes. Now i have no idea how to talk to my nextauth signin/signup. Does anyone has an idea on how to do that?
No updates. #2294 might be relevant, but my focus is elsewhere right now.
This should be a priority for the project, really needed.
@mataide Please only provide useful feedback to the conversation. 😃 If it was needed, the discussion around probably would be much bigger (and more meaningful, as reading back, only a few comments are actually focusing on helping), and more people would be standing in line to help out with the implementation. Feel free to open a PR if you have a good idea!
General advice, remember the purpose of open source! :pray:
Closing this in favor of #2294.
The core has been refactored to be Next.js agnostic (#2857), so feel free to experiment with what is exported from next-auth/core
.
Nothing has been documented about this and should be considered experimental, but you are free to try it out!
I'm working on a proof of concept for this. With a fairly minor change to next auth and using react native expo (also with a minor change) i've got the majority of the flow working. I'll try bundling it all up into a single demo repo.
any updates for this, it should be something that is implemented on day one
Any updates? This feature is fundamental!
I neeeeeed this 🙏
i'm waiting.
I had a similar need because I wanted to run my requests through my Insomnia client.
I looked at the network tab and just reverse engineered the requests.
Instruction assumptions:
localhost
3000
GET
request to http://localhost:3000/api/auth/csrf
. Response will look something like
{
"csrfToken": "cf3c89881118f3dcecbbd0616be6481475d3c23de3f5ae7a9a1bdfa59739bc78"
}
csrfToken
and send it in a Form URL encoded request to http://localhost:3000/api/auth/callback/credentials?
with the following form values:
csrfToken
previous obtained value from /api/auth/csrf
username
or however your credentials are set uppassword
or however your credentials are set upjson
set to true
Values example
Insomnia example of encoding
What you post needs to map to how your [...nextauth].js
file is setup. Mine is set up for credentials
. Example
End result will be a cookie that exists under next-auth.session-token
. This appears to be a base64 encoded JSON web token using your NEXTAUTH_SECRET
, but I haven't verified it. Just decoded the raw string with https://www.base64decode.org/
Depending on your environment / client / provider, you might have more work to do, but this should be possible for most folks.
useSession
now works on API routes and I'm able to test outside of my application / see what is secured and what isn't in my REST client. These instructions will likely also work for running integration tests outside of a browser context.
useSession
inside of my API routes now provides a response like:
session {
user: { name: 'test', email: 'test@gmail.com' },
expires: '2023-02-10T16:08:16.467Z'
}
Finally, a friendly reminder that your browser's network tab is your friend. Rather than complaining in the thread / asking for @balazsorban44 to refactor, take some time to see if you can find a workaround.
Appreciate all the work you've done here, @balazsorban44
I want to verify the user's session in an edge function. I'm using a db strategy so I need to query an endpoint that checks the db for me. I get the session cookie in the request object but I can't figure out how to authenticate it against the 'localhost:3000/api/auth/session'
Using postman I get an empty object in response, so I know it's reaching the endpoint. It's just not giving me any information. I also included a valid csrf-token and the session-token as cookies. Didn't change at thing. How can I fault trace this? Is it even possible? Or should I just implement my own /auth endpoint? ^^
I spent couple hours debugging this. I was doing what @olingern suggested. But there was something missing.
For whatever reason the csrfToken
that you get in the body from the request to /api/auth/csrf
is different that the csrfToken
that comes in the same request but as a cookie.
The one in the body is incomplete, it's missing a part that includes a bar and then a string |XXXXXXXX
.
Once I started using the csrfToken from the cookie it worked.
The reason why it works in insomnia for @olingern is because insomnia send the cookie in the request.
So the steps are:
/api/auth/csrf
, grab the next-auth.csrf-token
value from the Set-Cookie
headernext-auth.session-token
from the set-cookie
header and use it for further authenticated requestsit doesn't work on my case, i follow both @rickitan and @olingern solution but didn't get the session-token back. I use custom config credentials. And i follow the field nicely but didn't work. credentials: { countryCode: { label: 'Country Code', type: 'text', placeholder: '', }, phoneNumber: { label: 'Phone Number', type: 'text', placeholder: '', }, email: { label: 'Email', type: 'text', placeholder: '', }, password: { label: 'Password', type: 'password', }, role: { label: 'Role', type: 'text', placeholder: '', }, },
And it return this value : { "url": "http://localhost:3000/api/auth/signin?csrf=true" } which is the login form. Why is it so? why don't it straight away login ?
And it return this value : { "url": "http://localhost:3000/api/auth/signin?csrf=true" } which is the login form. Why is it so? why don't it straight away login ?
You have to check in the cookies for the session token.
I spent couple hours debugging this. I was doing what @olingern suggested. But there was something missing.
For whatever reason the
csrfToken
that you get in the body from the request to/api/auth/csrf
is different that thecsrfToken
that comes in the same request but as a cookie.The one in the body is incomplete, it's missing a part that includes a bar and then a string
|XXXXXXXX
.Once I started using the csrfToken from the cookie it worked.
The reason why it works in insomnia for @olingern is because insomnia send the cookie in the request.
So the steps are:
- Call
/api/auth/csrf
, grab thenext-auth.csrf-token
value from theSet-Cookie
header- Send it both in the body and the cookie:
- Grab the
next-auth.session-token
from theset-cookie
header and use it for further authenticated requests
Would it work for signing in with providers other than username / password, with github for example?
just switch to supabase or appwrite, easiest way to get everything you need. Next Auth is free and open source, can't always get what you want.
It works for me. I hope it helps you.
Auth Config
/**
* Options for NextAuth.js used to configure adapters, providers, callbacks, etc.
*
* @see https://next-auth.js.org/configuration/options
*/
export const authOptions: NextAuthOptions = {
session: {
strategy: "jwt",
},
callbacks: {
session({ session, token }) {
if (session.user) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
session.user.id = token.sub!;
}
return session;
},
},
adapter: PrismaAdapter(db) as Adapter,
providers: [
CredentialsProvider({
id: 'credentials',
name: "Credentials",
credentials: {
email: { type: "email" },
password: { type: "password" },
},
authorize: authorize(db),
}),
/**
* ...add more providers here.
*
* Most other providers require a bit more work than the Discord provider. For example, the
* GitHub provider requires you to add the `refresh_token_expires_in` field to the Account
* model. Refer to the NextAuth.js docs for the provider you want to use. Example:
*
* @see https://next-auth.js.org/providers/github
*/
],
};
Vue APP
const form = reactive({
username: null,
password: null,
})
const onSubmit = async () => {
console.log('submit!')
console.log(form.password, form.username)
if (!form.username || !form.password) {
ElMessage.error('Please input username and password!')
return
}
const csrfRequest: {
csrfToken: string
} = await fetch(`/api/auth/csrf`).then((res) => res.json())
const body = Object.entries({
csrfToken: csrfRequest.csrfToken,
email: encodeURIComponent('123@123.com'),
password: encodeURIComponent('123'),
callbackUrl: encodeURIComponent('/'),
redirect: false,
json: true,
})
.map(([key, value]) => `${key}=${value}`)
.join('&')
try {
const loginRes = await fetch(`/api/auth/callback/credentials?`, {
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body,
method: 'POST',
credentials: 'include',
})
if (loginRes.status === 200) {
const userInfo: {
user: {
email: string
id: string
}
expires: string
} = await fetch(`/api/auth/session`).then((res) => res.json())
if (userInfo.user.email !== form.username) {
ElMessage.error('Login failed! Please check your username and password!')
return
}
localStorage.setItem('userInfo', JSON.stringify(userInfo))
ElMessage.success('Login success!')
} else {
ElMessage.error('Login failed! ' + loginRes.statusText)
}
} catch (error) {
console.error(error)
ElMessage.error('Login failed!')
}
}
It works for me. I hope it helps you.
Auth Config
/** * Options for NextAuth.js used to configure adapters, providers, callbacks, etc. * * @see https://next-auth.js.org/configuration/options */ export const authOptions: NextAuthOptions = { session: { strategy: "jwt", }, callbacks: { session({ session, token }) { if (session.user) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion session.user.id = token.sub!; } return session; }, }, adapter: PrismaAdapter(db) as Adapter, providers: [ CredentialsProvider({ id: 'credentials', name: "Credentials", credentials: { email: { type: "email" }, password: { type: "password" }, }, authorize: authorize(db), }), /** * ...add more providers here. * * Most other providers require a bit more work than the Discord provider. For example, the * GitHub provider requires you to add the `refresh_token_expires_in` field to the Account * model. Refer to the NextAuth.js docs for the provider you want to use. Example: * * @see https://next-auth.js.org/providers/github */ ], };
Vue APP
const form = reactive({ username: null, password: null, }) const onSubmit = async () => { console.log('submit!') console.log(form.password, form.username) if (!form.username || !form.password) { ElMessage.error('Please input username and password!') return } const csrfRequest: { csrfToken: string } = await fetch(`/api/auth/csrf`).then((res) => res.json()) const body = Object.entries({ csrfToken: csrfRequest.csrfToken, email: encodeURIComponent('123@123.com'), password: encodeURIComponent('123'), callbackUrl: encodeURIComponent('/'), redirect: false, json: true, }) .map(([key, value]) => `${key}=${value}`) .join('&') try { const loginRes = await fetch(`/api/auth/callback/credentials?`, { headers: { 'content-type': 'application/x-www-form-urlencoded', }, body, method: 'POST', credentials: 'include', }) if (loginRes.status === 200) { const userInfo: { user: { email: string id: string } expires: string } = await fetch(`/api/auth/session`).then((res) => res.json()) if (userInfo.user.email !== form.username) { ElMessage.error('Login failed! Please check your username and password!') return } localStorage.setItem('userInfo', JSON.stringify(userInfo)) ElMessage.success('Login success!') } else { ElMessage.error('Login failed! ' + loginRes.statusText) } } catch (error) { console.error(error) ElMessage.error('Login failed!') } }
@zsnmwy while this works for a simple case, with simple email/password login, this doesn't seem to work for cases like two factor authentication, where you wait for confirmation, or even simpler, when accounts do not log in. The problem is that nextjs keeps returning the whole HTML page for /auth/callback/credentials
, so your code will always be 200, no matter if successful or not, because you always get the HTML response. It's pretty inconvenient and it's a lot of trouble to head into.
@Dragosp33 Thanks for your feedback. I'm not checking in the 2fa. The simple login method is enough for my project. If you have any good techniques, please let me know.
@zsnmwy I'm currently still working on that, but it feels more like a "hack" rather than a solution, as the next auth API endpoint for signing in returns a HTML page as response, so what could be done is displaying the code or message in the HTML page returned by the auth endpoint, and get that message by the element id from the page and handling it in the external app. Otherwise I don't see a solution for this situation
Can i know how to login via flutter app by using next auth credentials. I can't find a solution
With react native and axios it works fine
private async getCsrfToken(): Promise<string> {
const { data: csrfRequest } = await this.api.get("/auth/csrf");
return csrfRequest.csrfToken;
}
private async performLogin(credentials: LoginCredentials, csrfToken: string): Promise<AxiosResponse> {
const body = this.createLoginBody(credentials, csrfToken);
return this.api.post("/auth/callback/credentials", body, {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
withCredentials: true,
});
}
private createLoginBody(credentials: LoginCredentials, csrfToken: string): string {
return Object.entries({
csrfToken,
email: encodeURIComponent(credentials.email),
password: encodeURIComponent(credentials.password),
callbackUrl: encodeURIComponent("/"),
redirect: false,
json: true,
})
.map(([key, value]) => `${key}=${value}`)
.join("&");
}
private async getUserInfo(): Promise<UserInfo> {
const { data: userInfo } = await this.api.get<UserInfo>("/auth/session");
return userInfo;
}
async login(credentials: LoginCredentials): Promise<AuthResponse | undefined> {
const csrfToken = await this.getCsrfToken();
const loginResponse = await this.performLogin(credentials, csrfToken);
if (loginResponse.status === 200) {
const userInfo = await this.getUserInfo();
return this.handleSuccessfulLogin(userInfo, credentials.email);
}
}
However, I noticed that when running my Next.js locally, the authentication doesn't work. But it works in production. It could be something in my project's configurations.
Hi @maldee Did you find solution? I tried with thsi but I counldn't find session token in cookie list:
final response = await tokenClient.request(
UrlContainer.loginUrl,
options: Options(method: Method.postMethod, headers: {
"Content-Type": "application/x-www-form-urlencoded",
}),
data: {
"csrfToken": csrfToken,
"email": emailController.text,
"password": passwordController.text,
"json": true,
},
);
if (response.statusCode == 200) {
// Extract cookies from the response
final cookies = response.headers.map['set-cookie'];
if (cookies == null) {
throw Exception('No cookies found in the response');
}
}
I send the cookie to the app through deep links. You can capture the cookie using query parameters and use it in the HTTP requests.
Your question
How to use
next-auth
API endpoints (signin/signout) from a mobile app, to make the user signin/signout so as to consume the API created in NextJS from mobile apps?What are you trying to do I have a doubt/question?
next-auth
API endpoints (signin/signout) from a mobile app, to make the user signin/signout so as to consume the API created in NextJS from mobile apps?Any help would be highly appreciated…
Reproduction
Feedback Documentation refers to searching through online documentation, code comments and issue history. The example project refers to next-auth-example.