okta-sm
v4.0.1
Published
Okta Session Manager
Readme
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#pkceDependencies
<!-- 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 containingel- the okta widget element selectoronSuccess- a success callback function that gets called after retrieving tokens withgetTokensWithoutPrompt()or if the widget is configured to use theimplicit flowonError- 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())
}
}