okta / okta-vue

OIDC SDK for Vue
https://github.com/okta/okta-vue
Other
46 stars 25 forks source link

"AuthSdkError: Unable to parse a token from the url" #20

Open reesewesterhoff opened 4 years ago

reesewesterhoff commented 4 years ago

I'm submitting a:

Current behavior

I am using the Okta sign in widget running at http://localhost:8080 as a login page. Here is the code for that.

// index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <title>Login Widget</title>
    <script src="https://global.oktacdn.com/okta-signin-widget/4.3.3/js/okta-sign-in.min.js" type="text/javascript"></script>
    <link href="https://global.oktacdn.com/okta-signin-widget/4.3.3/css/okta-sign-in.min.css" type="text/css" rel="stylesheet"/>
  </head>
  <body>
    <div class="container">
      <div id="okta-login-container"></div>
    </div>
    <script type="text/javascript">
      var oktaSignIn = new OktaSignIn({
        baseUrl: "https://XXXXXXXXX.okta.com",
        clientId: "XXXXXXXXXXXXXXXXXX",
        redirectUri: "http://localhost:8081/implicit/callback",
        authParams: {
          issuer: "https://XXXXXXXXXX.okta.com/oauth2/default",
          responseType: ['token', 'id_token'],
          display: 'page'
        },
      });

      if (oktaSignIn.hasTokensInUrl()) {
        console.log('has tokens', oktaSignIn)
      } else {
        console.log('no tokens')
        oktaSignIn.renderEl(
          { el: '#okta-login-container' },
          function success(res) {},
          function error(err) {
            console.error(err);
          }
        );
      }
    </script>
  </body>
</html>

Upon a successful login, the browser is redirected to http://localhost:8081/implicit/callback and there is a code sent along with it so the url looks something like this: http://localhost:8081/implicit/callback?code=bigStringOfNumbersAndLetters&state=anotherBigStringOfNumbersAndLetters

My vue app is running on http://localhost:8081 and the two files I changed to handle the authentication are as follows:

// router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Auth from '@okta/okta-vue'

Vue.use(VueRouter)
Vue.use(Auth, {
  issuer: 'https://XXXXXXXXXXX.okta.com/oauth2/default',
  clientId: 'XXXXXXXXXXXXXXXX',
  redirectUri: 'http://localhost:8080/implicit/callback',
  scopes: ['openid', 'profile', 'email'],
  pkce: false
})

  const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  { path: '/implicit/callback', component: Auth.handleCallback() }
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

// App.vue

<template>
  <div id="app">
    <router-link to="/" tag="button" id='home-button'> Home </router-link>
    <button v-if='authenticated' v-on:click='logout' id='logout-button'> Logout </button>
    <button v-else v-on:click='login' id='login-button'> Login </button>
    <router-view/>
  </div>
</template>

<script>

export default {
  name: 'app',
  data: function () {
    return {
      authenticated: false
    }
  },
  created () {
    this.isAuthenticated()
  },
  watch: {
    // Everytime the route changes, check for auth status
    '$route': 'isAuthenticated'
  },
  methods: {
    async isAuthenticated () {
      this.authenticated = await this.$auth.isAuthenticated()
    },
    login () {
      // this.$auth.loginRedirect('/')
    },
    async logout () {
      await this.$auth.logout()
      await this.isAuthenticated()

      // Navigate back to home
      this.$router.push({ path: '/' })
    }
  }
}
</script>

When the sign in widget redirects to http://localhost:8081/implicit/callback?code=bigStringOfNumbersAndLetters&state=anotherBigStringOfNumbersAndLetters an error is logged in the console and the app breaks. image

Expected behavior

  1. Use the sign in widget for a login screen.
  2. After a successful login redirect the browser to the http://my-vue-app.com/implicit/callback?code=bigStringOfNumbersAndLetters&state=anotherBigStringOfNumbersAndLetters.
  3. Have the Auth.handleCallback() take the info from the url and set the tokens/relevant information into the session/local storage.
  4. Return the browser to http://my-vue-app.com/ with with user authenticated.

Minimal reproduction of the problem with instructions

See above

Extra information about the use case/user story you are trying to implement

Environment

swiftone commented 4 years ago

@reesewesterhoff - thanks for the report. I'll try to reproduce your case to confirm the issue as soon as I can, but looking at the surface I'd guess that your signin-widget is using PKCE, while your okta-vue is not.

Do things clear up if you add pkce: false to the authParams you pass to the widget config?

aarongranick-okta commented 4 years ago

@reesewesterhoff Alternatively, remove pkce: false from your Vue code. true is the default and recommended setting for pkce option. The value for this setting must match between the signin-widget and Vue service.

reesewesterhoff commented 4 years ago

Thanks for the quick response! @swiftone Adding pkce: false to the authParams in the widget worked! With both of them having a matching type everything works as expected. @aarongranick-okta When I tried setting pkce: true or removing that line of code from both the widget and the vue app I got this error: image There is a good chance that I just have not set something up appropriately. Any chance you know what it is off the bat or could you point me in the direction of some docs that would help me set that up?

BryceV commented 3 years ago

^ I can confirm adding pkce: false removed this error. My app was broken when I just removed that field.

shuowu commented 3 years ago

@reesewesterhoff @BryceV Can you try the Okta Vue custom-signIn sample? I verified it locally, it works for both PKCE and implicit flows.

BryceV commented 3 years ago

For the sample (implicit flow) I get:

Screen Shot 2020-10-14 at 9 29 26 AM
shuowu commented 3 years ago

@BryceV The error is caused by attempting to trigger multiple login flow concurrently. If you have not changed any logic in the samples, probably you have code=xxx in your URL, which triggered the protection.

Code reference: https://github.com/okta/okta-auth-js/blob/master/lib/token.ts#L592

mabarbeau commented 3 years ago

This could be related to https://github.com/okta/okta-auth-js/issues/474