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

Trying to use with keycloak-passport #39

Closed
garmeeh opened this issue Aug 11, 2018 · 17 comments
Closed

Trying to use with keycloak-passport #39

garmeeh opened this issue Aug 11, 2018 · 17 comments
Labels
bug Something isn't working question Ask how to do something or how something works

Comments

@garmeeh
Copy link

garmeeh commented Aug 11, 2018

I have been trying to use next-auth with this keycloak-passport Strategy. (I did have to modify the strategy's name to be lowercase to be able to test it out)

I can log in no problem and it creates a session. Only problem is, getProfile() doesn't seem to fire at all so the session just contains the csrfSecret but no user. Keycloak recognises I'm already logged in when trying to log in.

Have been trying to debug through what could be happening but couldn't get to the bottom of it. Any direction on what might be the issue would be great. If I get it working would be happy to submit some documentation on it.

@iaincollins
Copy link
Member

I haven't used that strategy before, but in theory they should all work (of course the oAuth spec is a bit vague on the details of profiles, so reality is different).

The getProfile() function should be fired on line 77 of next-auth/src/passport-strategies.js, and passed a profile object as returned by the remote service (even if it's null).

Can you see if your getProfile() function in next-auth.providers.js fires (e.g. console.log) and the 'profile' object in your is null or contains anything?

To debug you could hard code a user object response in getProfile() that looks something like this to see if that helps.

getProfile(profile) {
 console.log("Got profile from keycloak: ", profile)
  return {
    id: "123",
    name: "J Smith"
    email: "j.mith@example.com"
  }
}

The fields you need are 'id', 'name' and email. If you don't get an email address from the service (e.g. sites like Twitter don't return it unless you explicitly request it) you can use something like ${profile.id}@localdomain.com.

Another thing to watch for is some providers require explicit options, like scope, e.g.:

providerOptions: {
  scope: ['profile', 'email']
},

Next.js refreshes the output on the console so can be handy to do something like npm run dev > debug.log | tail -f debug.log to log the output for debugging.

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

I've just looked at #38 raised by @mBeierl and I think the same issue impacts this strategy.

https://github.com/exlinc/keycloak-passport

It passes a different list of arguments in the callback (accessToken, refreshToken, profile, done) but next-auth is expecting the strategy to return (req, accessToken, refreshToken, _profile, next).

I thought the method signature for this callback was standardised in all strategies (because it works this way in Google, Facebook and Twitter and a few others) but I guess not in the wild!

It's easy to hack for a specific strategy (e.g. fork the strategy and change what it returns) as a workaround but I'm not sure what the best way to handle different responses in strategies like this is (as there is already too much complexity to configuration and I should be focusing on reducing it :-).

I'll have a think and see what we can do!

@iaincollins iaincollins added the bug Something isn't working label Aug 11, 2018
@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

Thanks for looking into it 😄

Yeah trying that snippet in the getProfile and no joy. I am testing this out in your example so added a console to line 76 of next-auth/src/passport-strategies.js and it doesn't get fired. Based on your comment I'm assuming this is due to the difference in method signatures?

@iaincollins
Copy link
Member

It looks like it uses the library https://github.com/jaredhanson/passport-oauth2 which is what's returning the different signature.

I'm not sure how you can solve this compatibility issue easily, with maybe having your own version of keycloak-passport. :-(

The keycloak-passport strategy doesn't seem to do too much, I wonder if a generic oAuth 2 module for Passport (other than err passport-oauth2… there seem to be a few at least!) might work in this case?

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

I'm not sure how you can solve this compatibility issue easily, with maybe having your own version of keycloak-passport. :-(

Lookinking more likely I might just have go this route 😢

The keycloak-passport strategy doesn't seem to do too much, I wonder if a generic oAuth 2 module for Passport (other than err passport-oauth2… there seem to be a few at least!) might work in this case?

Not 100% sure by what you mean here 🤔

@iaincollins
Copy link
Member

iaincollins commented Aug 11, 2018

Hmm looking at the options that may not be as easy as I thought.

Can you paste in your config for the provider from next-auth/src/passport-strategies.js?

I think I have a fix I can suggest.

@iaincollins
Copy link
Member

Basically, in your strategyOptions add passReqToCallback with a value of true and it should work!

strategyOptions: {
  /* other options */
  passReqToCallback: true
},

It seems the underlying module keycloak-passport uses respects this option and will return the method signature you need so will be compatible. :-)

@iaincollins
Copy link
Member

Oh wait boo, I just realised next-auth already does this for you! Damn. Nevermind that then.

So err sorry something else is going on with the service. :-(

keycloak-passport uses passport-oauth2 under the hood and there are a bunch of open issues about callbacks not firing there. I'm not sure what's going on or how you can fix it, as it seems like it's not something next-auth can fix. :-/

I would maybe as the maintainer of passport-keycloak if they have any tips.

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

providers.push({
    providerName: 'keycloak',
    Strategy: KeycloakStrategy,
    strategyOptions: {
      host: 'https://www.site.com',
      authorizationURL:
        'https://www.site.com/auth/realms/site/protocol/openid-connect/auth',
      tokenURL:
        'https://www.site.com/auth/realms/site/protocol/openid-connect/token',
      userInfoURL:
        'https://www.site.com/auth/realms/site/protocol/openid-connect/userinfo',
      realm: 'realm',
      clientID: 'web-client',
      clientSecret: 'SECRET',
      callbackURL: '/auth/callback',
      passReqToCallback: true
    },
    getProfile(profile) {
      console.log('Got profile from keycloak: ', profile);
      return {
        id: '123',
        name: 'J Smith',
        email: 'j.mith@example.com'
      };
    }
  });

This is my config. No joy with the suggestion 😑

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

Thanks for the help. I will open an issue over @passport-keycloak. If I make any progress, I will update this issue.

@iaincollins
Copy link
Member

iaincollins commented Aug 11, 2018

Okies, so you can remove passReqToCallback as it already adds it, but one last thing to try:

  1. Remove callbackURL and let it be set automatically, as the current value (/auth/callback) isn't right.

  2. If you need to set it manually, set it to /auth/oauth/keycloak/callback (you can also specify your servers protocol and hostname, name like: http://localhost:300/auth/oauth/keycloak/callback)

(The keycloak bit in the callback URL isn't special, it just needs to match whatever you have put in as the providerName, which is currently set to keycloak.)

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

😄 Nice one

So removing the callback and setting my host to http://localhost:300/auth/oauth/keycloak/callback has moved me along. I can now log in and it returns the correct profile. It also updates the session as expected.

Not sure if this is related but if I click log out I now get this screen if trying to log in again:

image

@iaincollins
Copy link
Member

Hmm no that should not be related, but I'm not sure what's causing that.

You might want to close down your browser, stop and start the service again and try and replicate it.

In development mode, Next.js does hot-reloading and caches pages in Service Workers and browser behaviour can get weird if you stop and start things and the only way to clear it out is to close and re-open the browser. Both those things (which only happen in development mode on Next.js projects) cause weird page refreshes.

PS: Thanks for reminding me a I need to fix a typo on that that example error page (just pushed that).

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

Tried it in a new browser in production mode and no joy, still not allowing me to log in after logging out. Interestingly if I stop and start the server it authenticates me when I click sign in, so looks like it's not actually logging me out correctly.

But as far as the original issue goes I think we can close it? I will do a bit more digging on this logging out issue and see can I get to the bottom of it. It seems like I am not actually being logged out.

😆 I'm terrible for typos so didn't even notice

@garmeeh
Copy link
Author

garmeeh commented Aug 11, 2018

Thanks for all the help with this by the way! 💪

@iaincollins
Copy link
Member

You welcome! And great yes, lets close this off so it's easy for anyone to follow if they find it when Googling in case they have the same thing. :-) Happy to help with the separate log out issue!

The logout button code should be pretty simple, so hopefully won't involve too much debugging.

You might want to take look at the handleSignoutSubmit() function in the nextjs-starter project if it helps. You absolutely don't need to set the cookie like it does, but it can be nice user behaviour (as it signs them out but keeps them on the same page).

@thebetterjort
Copy link

Did you solve this or have a repo that has a basic implementation of nextjs + keycloak?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Ask how to do something or how something works
Projects
None yet
Development

No branches or pull requests

3 participants