4.0.1 • Published 1 year ago

okta-sm v4.0.1

Weekly downloads
-
License
-
Repository
-
Last release
1 year ago

okta-sm (pkce version)

Okta Session Manager

This version defaults to use PKCE if the browser supports it. PKCE uses the authorization_code flow which returns both id_token and token. If not support, implicit flow is used.

Installation

# installs directly from github branch
npm install BIAD/okta-sm#pkce

Dependencies

<!-- Latest CDN production Javascript and CSS -->
<script
    src="https://global.oktacdn.com/okta-signin-widget/3.9.2/js/okta-sign-in.min.js"
    type="text/javascript"
></script>

<link
    href="https://global.oktacdn.com/okta-signin-widget/3.9.2/css/okta-sign-in.min.css"
    type="text/css"
    rel="stylesheet"
/>

Configuration

import OktaSM from 'okta-sm'

// keep a reference to the object OR...
let oktaSm = new OktaSM({
    auth: {
        clientId: process.env.VUE_APP_OKTA_ID,
        baseUrl: process.env.VUE_APP_OKTA_BASE_URL,
        issuer: process.env.VUE_APP_OKTA_ISSUER,
        redirectUri: process.env.VUE_APP_OKTA_REDIRECT_URI,
        authParams: {
            // // it's fine to include issuer here, but it's no longer needed b/c the code checks for auth.issuer
            // issuer: process.env.VUE_APP_OKTA_ISSUER,
            // // the responseType now only applies if pkce is not supported by the browser (defaults to both tokens)
            // responseType: ['token', 'id_token'],
            scopes: ['openid', 'profile', 'email']
        },
        idps: [
            {
                id: process.env.VUE_APP_OKTA_ITRUST_IDP,
                text: 'Login With iTrust',
                className: 'idp-itrust'
            }
        ]
    },
    // include keydown for a11y support
    listenerTypes: ['mousemove', 'mousedown', 'keydown'],
    session: {
        // 2.5 minutes for alert
        maxAlertDuration: 2.5,
        // 30 minutes for inactivity
        maxInactivity: 30
    }
})

// use the Vue plugin
// access the instance in your components with this.$sm (short for session manager)
Vue.use(OktaSM, {
    // options
})

Usage

mount()

:hourglass: async

This initializes the OktaSM object and, if the user is already authenticated, begins tracking user activity.

oktaSm.mount()

beforeDestroy()

This is only necessary if mount() could get called multiple times before a full page reload (e.g. if mount() is called in a child component of App)

oktaSm.beforeDestroy()

events.on('SHOW_TIMEOUT')

This event listener provides a notification when the user has reached maxInactivity - maxAlertDuration time of inactivity.

oktaSm.events.on('SHOW_TIMEOUT', () => {
    // show timeout component
    this.showTimeoutComponent = true
    // listen for timeout component events
    this.$refs.TimeoutComponent.$on('expired', () => {
        // user is inactive - logout by removing tokens
        oktaSm.userDidntRespond()
        this.showTimeoutComponent = false
    })
    this.$refs.TimeoutComponent.$on('not-expired', () => {
        // user is active - extend their session
        oktaSm.userDidRespond()
        this.showTimeoutComponent = false
    })
})

time

An object containing the real-time millisecond values for lastActive and expiresIn for use in your custom TimeoutComponent.

interface time {
    lastActive: number
    expiresIn: number
}

events.on('RENEWAL_ERROR' | 'OAUTH_ERROR' | 'LOGIN_REQUIRED')

Optional error listeners:

  • RENEWAL_ERROR: A problem occurred when trying to extend the tokens
  • OAUTH_ERROR: A problem occurred during authentication (e.g. user not assigned)
  • LOGIN_REQUIRED: Okta session is expired, but application attempted to extend the tokens

auth.checkSessionAndLogin({el: string}, onSuccess, onError)

:warning: This method requires access to third party cookies :hourglass: async

If the user is not authenticated - check with auth.isAuthenticated() - call this function to retrieve tokens.

  • options - an object containing el - the okta widget element selector
  • onSuccess - a success callback function that gets called after retrieving tokens with getTokensWithoutPrompt() or if the widget is configured to use the implicit flow
  • onError - an error callback function that gets called if an OAuthError occurs
oktaSm.auth.checkSessionAndLogin(
    { el: '#okta-widget' },
    (...args) => {
        console.log('tokens', ...args)
        if (document.getElementById('okta-widget')) {
            // removes the widget from the dom
            oktaSm.auth.widget.remove()
        }
    },
    (error) => {
        alert(error)
    }
)

auth.hasTokensInUrl()

Call this when page loads to check if a PKCE redirect flow is active.

if (oktaSm.auth.hasTokensInUrl()) {
    try {
        await oktaSm.auth.handleTokensInUrl()
    } catch (error) {
        // probably the user is not assigned to the app
        alert(error)
    }
}

auth.isAuthenticated()

:warning: This method requires access to third party cookies :hourglass: async

Returns true if a session exists and an access token exists. Without an access token, the API's cannot be reached. And without a session, an expired access token cannot be extended.

Note: This has a side-effect due to checking for an active session. Each time session is queried, it extends the lifetime of the session.

if (!(await oktaSm.auth.isAuthenticated())) {
    oktaSm.auth.checkSessionAndLogin(/* see above */)
}

auth.getAccessToken()

:hourglass: async

Get the access token from storage if it exists.

fetch('/todos', {
    headers: {
        Authorization:
            'Bearer ' + (await oktaSm.auth.getAccessToken()).accessToken
    }
})

auth.getIdToken()

:hourglass: async

Same as above.

auth.getUserInfo()

:hourglass: async

Get claims about the user.

class User {
    name: string
    email: string
    roles: string[]
    groups: string[]
}

new User(await oktaSm.auth.getUserInfo())

auth.logout()

:warning: This method requires access to third party cookies :hourglass: async

Deletes the Okta session across all applications.

<v-btn @click="logout">Logout</v-btn>

<script>
    export default {
        name: 'NavComponent',

        methods: {
            async logout() {
                await oktaSm.auth.logout()
            }
        }
    }
</script>

Routing

Vue users can use the built-in OktaSM.RouteGuard which checks that the user is authenticated if the route requires it. Clients with a different framework or that require more customization will need to supply their own logic.

OktaSM.RouteGuard

/* main.js */
// the RouteGuard expects the plugin to be called
Vue.use(OktaSM, {
    // options
})

/* router.js */
let router = new VueRouter({
    // options
})
let routeGuard = new OktaSM.RouteGuard(Vue)
router.beforeEach(
    // redirect to /login if user is not logged in
    routeGuard.authRedirectGuard('/login')
)

getPreAuthRoute()

If using OktaSM.RouteGuard the last route gets saved before being redirected to /login

/* Login.vue */
export default {
    name: 'Login',

    mounted() {
        oktaSm.auth.checkSessionAndLogin(
            options,
            () => {
                // ...
                // the RouteGuard saves the last path before being redirected to Login page
                this.$router.replace(oktaSm.getPreAuthRoute())
                // ...
            },
            (error) => {}
        )
    }
}

/* LoginCallback.vue */
// This is the component that is routed to from the redirectUri
export default {
    name: 'LoginCallback',

    async mounted() {
        await oktaSm.auth.handleTokensInUrl()
        this.$router.replace(oktaSm.getPreAuthRoute())
    }
}
4.0.1

1 year ago