okta / okta-oidc-js

okta-oidc-js
https://github.com/okta/okta-oidc-js
Other
395 stars 232 forks source link

With idp added to config, I can't login to my app with either idps or the okta signIn widget #327

Open hezaaron opened 6 years ago

hezaaron commented 6 years ago

I'm using angular 6. I have this config in app module:

...
import { OktaAuthModule, OktaAuthGuard, OktaCallbackComponent } from '@okta/okta-angular';
...

const oktaConfig = {
    issuer: 'https:{OktaDomain}/oauth2/default',
    clientId: '{ClientId}',
    redirectUri: 'http://localhost:4200'
}

imports[
...
OktaAuthModule.initAuth(oktaConfig),
....
]

This works fine with the signIn widget configured like so:

widget = new OktaSignIn({baseUrl: '{orgUrl}'});

But when I add idp config to the signin widget like so:

widget = new OktaSignIn({
    baseUrl: '{orgUrl}',
    clientId: '{clienId}',
    redirectUri: 'http://localhost:4200',
    authParams: {
        issuer: '{OktaDomain}/oauth2/default',
        responseType: ['id_token', 'token'],
        scopes: ['openid', 'email', 'profile']
    },
    idps:[
          { type: 'google', id: '{id}' }
        ],
    idpDisplay: "PRIMARY"
});

login no longer works instead it says "Cannot read property 'token' of undefined"

robertjd commented 6 years ago

Hi @hezaaron , do you also see an error in the URL bar when this happens? When the user is sent back to your application there may be an error that is added as a query parameter to the redirect URL, this error would have more information.

hezaaron commented 6 years ago

Hi @robertjd, thanks for attending to my query! No, there's no error in the URL bar only in the web console where it says "... cannot read property 'token' of undefined." I'm trying to use the token that a success login should return somewhere in my application. I think that's the reason for the error since login is not working after that social login config.

However, using this example: https://developer.okta.com/blog/2017/09/19/build-a-secure-notes-application-with-kotlin-typescript-and-okta, I created custom authService and authGuard and removed the ones from okta angular sdk. So it's working now with social login added to the widget.

jmelberg-okta commented 5 years ago

Hi @hezaaron,

What function are you trying to call that contains the token method/property? Do you have any special logic around the Widget (widget.token.hasTokensInUrl() or widget.token.parseTokensFromUrl())?

hezaaron commented 5 years ago

Hi @jmelberg-okta,

No I did not use any of those widget functions. But I Have in my login component:

this.widget.renderEl({el: '#okta-signin-container'}, (response) => {
    if(response.status === 'SUCCESS'){
        this.oktaService.loginRedirect('/', { sessionToken: response.session.token });
    }
},
(err) => {
    throw err;
});

After a user login, it doesn't redirect to '/'.

hezaaron commented 5 years ago

I have fixed it. The problem is in the below line of code

this.oktaService.loginRedirect('/', { sessionToken: response.session.token });

'token' is undefined because it is no longer in the response given the configuration:

responseType: ['id_token', 'token']

As a result, what I have in the response is an array containing 'idToken' and 'accessToken'. So I changed the redirect function above to:

this.oktaService.loginRedirect('/', { sessionToken: response[0].idToken});

And that fixed the issue. Thank you for your time.

jmelberg-okta commented 5 years ago

Hi @hezaaron - The above snippet also will not work, as you're attempting to redirect to Okta with an idToken instead of a sessionToken.

The loginRedirect method is intended to redirect through Okta's /authorize endpoint. With a sessionToken, the user is immediately redirected back to your application.

I'm assuming this is what you're trying to do:

  1. Use the Sign-In Widget to receive a sessionToken. You'll need to omit the authParams in order to do so:
const widget = new OktaSignIn({
  baseUrl: 'https://{yourOktaDomain}',
  clientId: '{clientId}',
  redirectUri: '{redirectUri}'
});
  1. Next, render the Widget and pass the sessionToken to the Angular Auth Service:
widget.renderEl(
  { el: '#my-selector' },
  (res) => {
    // Use @okta/okta-angular to exchange the sessionToken for OAuth/OIDC tokens
    this.oktaService.loginRedirect('/', { sessionToken: res. sessionToken });
  },
  (error) => console.error(error);
);

Is this on track with what you're trying to do?

hezaaron commented 5 years ago

It is on track with what I'm trying to do and it works too with idps. But I had to include the authParams to add profile to scopes so I can retrieve the user's name. Please have a look at the complete code for my user auth service.

@Injectable()
export class UserAuthService {

    signIn = new OktaSignIn({
           baseUrl: 'https://{OktaDomain}',
           clientId: '{clientId}',
           redirectUri: '{redirectUrl}',
           authParams: {
               scopes: ['openid', 'email', 'profile']
           },
           idps:[
               { type: 'facebook', id: '{id}'},
               { type: 'google', id: '{id}' },
               { type: 'linkedin', id: '{id}'}
           ],
           idpDisplay: "PRIMARY",
           i18n: {
               en: {
                   'primaryauth.title': 'Sign In With',
                   'socialauth.facebook.label': 'Facebook',
                   'socialauth.google.label': 'Google',
                   'socialauth.linkedin.label': 'Linkedin'
               }
           }
    });

    constructor(private oktaService: OktaAuthService) {}

    showLogin() {
        this.signIn.renderEl({el: '#okta-signin-container'}, (response) => {
            if(response.status === 'SUCCESS'){
                this.signIn.tokenManager.add('idToken', response)
                this.oktaService.loginRedirect('/', { sessionToken: response.sessionToken});
            }
        },
        (err) => {
            throw err;
        });
    }

    get idTokenAsUser() {
        const token = this.signIn.tokenManager.get('idToken');
        return {
            name: token.claims.name,
            email: token.claims.email,
            username: token.claims.preferred_username
        };
    }
}

This works well. However, it may not be completely right, so please let me know your thought. Thanks