Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anonymous sessions #568

Closed
Delimer opened this issue Aug 11, 2020 · 14 comments
Closed

Anonymous sessions #568

Delimer opened this issue Aug 11, 2020 · 14 comments
Labels
incomplete Insufficient reproduction. Without more info, we won't take further actions/provide help. question Ask how to do something or how something works stale Did not receive any activity for 60 days

Comments

@Delimer
Copy link

Delimer commented Aug 11, 2020

How can anonymous sessions be used? It is necessary that before the user is authorized, it is possible to collect the data associated with him. For example, the items in the cart. Without sessions, I will not be able to add products on the server side, first I will need to store them on the client side and send them to the server side only after authorization.

@Delimer Delimer added the question Ask how to do something or how something works label Aug 11, 2020
@iaincollins
Copy link
Member

For items in a shopping cart a good approach is probably to use localStorage to store a JSON object with the content of their shopping cart as it will still be there after they sign in (and will be extremely fast for the user).

Once they sign in, you could take this further and assign an ID to the JSON object and take advantage of localStorage events to sync the cart with server side storage so that users can access the same cart on another computer / device they are signed into.

@iaincollins iaincollins added the incomplete Insufficient reproduction. Without more info, we won't take further actions/provide help. label Aug 13, 2020
@dackers86
Copy link

This would be an extremely useful feature.

Not everyone will want to create multiple solutions depending on authentication.

Firebase is one fo the few providers that shows a great example of this https://firebase.google.com/docs/auth/web/anonymous-auth.

The only drawback would be a cleanup of data for the Users table, should a session expire?

@stale
Copy link

stale bot commented Dec 5, 2020

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 ot open. Thanks!

@stale stale bot added the stale Did not receive any activity for 60 days label Dec 5, 2020
@stale
Copy link

stale bot commented Dec 12, 2020

Hi there! It looks like this issue hasn't had any activity for a while. To keep things tidy, I am going to close this issue for now. If you think your issue is still relevant, just leave a comment and I will reopen it. (Read more at #912) Thanks!

@stale stale bot closed this as completed Dec 12, 2020
@luisrudge
Copy link

for ecommerce, it's super important to have anonymous sessions. I'm working on a Commerce Tools ecommerce in Next.js and we need the ability to create a session for guest checkouts and things like this. I'd be happy to contribute a Commerce Tools provider with this support if anyone points me in the right direction.

@MRezaSafari
Copy link

isn't this possible in a new version with firebase adapter?

@jasperzeinstra
Copy link

for ecommerce, it's super important to have anonymous sessions. I'm working on a Commerce Tools ecommerce in Next.js and we need the ability to create a session for guest checkouts and things like this. I'd be happy to contribute a Commerce Tools provider with this support if anyone points me in the right direction.

@luisrudge did you find any solution for the commercetools guest checkout and having a token? Did you resolve it with NextAuth or did you move to something else?

@luisrudge
Copy link

@jasperzeinstra sorry, it's been a while 😬 I moved on to another company, but we did get it working with CT and Next Auth. If I remember correctly, we had two credential providers - one for anonymous sessions and the other for authenticated users. It worked reasonably well. Just remember to convert the anonymous sessions into actual sessions when the user authenticates, so the cart/order that was created is 'attached' to the user.

@MRezaSafari
Copy link

@jasperzeinstra sorry, it's been a while 😬 I moved on to another company, but we did get it working with CT and Next Auth. If I remember correctly, we had two credential providers - one for anonymous sessions and the other for authenticated users. It worked reasonably well. Just remember to convert the anonymous sessions into actual sessions when the user authenticates, so the cart/order that was created is 'attached' to the user.

do you have any example repo by any chance ?

@luisrudge
Copy link

@MRezaSafari sorry, I don't :(
But the important bits were something like this:

[
  CredentialsProvider({
    name: "anon",
    credentials: {},
    async authorize(credentials, req) {
      //no need to check anything here, just create a new CT anonymous session and return the token
      const authResult = await createAnonymousSession();
      /**
       * https://docs.commercetools.com/tutorials/anonymous-session#creating-a-token-with-a-new-anonymous-session
       * {
           "access_token": "vkFuQ6oTwj8_Ye4eiRSsqMeqLYNeQRJi",
           "token_type": "Bearer",
           "expires_in": 172800,
           "refresh_token": "{projectKey}:OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
           "scope": "view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey}"
         }
       */
      return { token: authResult.accessToken };
    },
  }),
  CredentialsProvider({
    name: "auth",
    credentials: {
      username: { label: "Username", type: "text" },
      password: { label: "Password", type: "password" },
    },
    async authorize(credentials, req) {
      //check for username password
      const authResult = await authenticateUserInCommerceTools(
        credentials.username,
        credentials.password
      );
      /**
         * https://docs.commercetools.com/api/authorization#password-flow
         * {
             "access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI",
             "expires_in": 172800,
             "scope": "view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} customer:{id}",
             "refresh_token": "{projectKey}:OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
             "token_type": "Bearer"
           }
         */

      //https://docs.commercetools.com/api/projects/me-profile
      const customerInfo = await getCustomerInformation(
        authResult.access_token
      );
      return { token: authResult.accessToken, ...customerInfo };
    },
  }),
];

@Nhollas
Copy link

Nhollas commented Apr 21, 2023

isn't this possible in a new version with firebase adapter?

How would it be possible? Have you got a repo bro? :)

@showduhtung
Copy link

@MRezaSafari sorry, I don't :( But the important bits were something like this:

[
  CredentialsProvider({
    name: "anon",
    credentials: {},
    async authorize(credentials, req) {
      //no need to check anything here, just create a new CT anonymous session and return the token
      const authResult = await createAnonymousSession();
      /**
       * https://docs.commercetools.com/tutorials/anonymous-session#creating-a-token-with-a-new-anonymous-session
       * {
           "access_token": "vkFuQ6oTwj8_Ye4eiRSsqMeqLYNeQRJi",
           "token_type": "Bearer",
           "expires_in": 172800,
           "refresh_token": "{projectKey}:OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
           "scope": "view_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey}"
         }
       */
      return { token: authResult.accessToken };
    },
  }),
  CredentialsProvider({
    name: "auth",
    credentials: {
      username: { label: "Username", type: "text" },
      password: { label: "Password", type: "password" },
    },
    async authorize(credentials, req) {
      //check for username password
      const authResult = await authenticateUserInCommerceTools(
        credentials.username,
        credentials.password
      );
      /**
         * https://docs.commercetools.com/api/authorization#password-flow
         * {
             "access_token": "v-dZ10ZCpvbGfwcFniXqfkAj0vq1yZVI",
             "expires_in": 172800,
             "scope": "view_published_products:{projectKey} manage_my_orders:{projectKey} manage_my_profile:{projectKey} customer:{id}",
             "refresh_token": "{projectKey}:OWStLG0eaeVs7Yx3-mHcn8iAZohBohCiJSDdK1UCJ9U",
             "token_type": "Bearer"
           }
         */

      //https://docs.commercetools.com/api/projects/me-profile
      const customerInfo = await getCustomerInformation(
        authResult.access_token
      );
      return { token: authResult.accessToken, ...customerInfo };
    },
  }),
];

say a guest leaves the page (possibly accidentally) and wants to reopen the page. How would you revalidate a previous guest?

@luisrudge
Copy link

@showduhtung you save the token result in the user session (via cookie or something else) so that browser will always reference the same guest.

@cleverlight
Copy link

cleverlight commented Oct 2, 2023

@luisrudge I've had a go at reconstituting a full example based on the helpful snippets you provided.

https://github.com/lightenna/nextjs-app-auth-anon-logins-example

I followed the two-provider model you eluded to:

export const authOptions: AuthOptions = {
    providers: [
        CredentialsProvider({
            name: "anonymous",
            credentials: {},
            async authorize(credentials, req) {
                return createAnonymousUser();
            },
        }),
        GithubProvider({
            clientId: process.env.GITHUB_CLIENT_ID as string,
            clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
        }),
    ],
    callbacks: {...}
    events: {...},
    session: {
        // use default, an encrypted JWT (JWE) store in the session cookie
        strategy: "jwt" as SessionStrategy,
    },
}
const handler = NextAuth(authOptions);

export {handler as GET, handler as POST}

Also, I've written up a short explanation of the crucial parts in a blog post.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
incomplete Insufficient reproduction. Without more info, we won't take further actions/provide help. question Ask how to do something or how something works stale Did not receive any activity for 60 days
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants