Created
October 3, 2020 01:47
-
-
Save K3TH3R/416e5c6627436fa87db16f57f50496d1 to your computer and use it in GitHub Desktop.
Vue3 version of Auth0 plugin from medium article: https://medium.com/@iamkether/provide-inject-async-plugins-with-vue3-e424525af6ae
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import createAuth0Client from '@auth0/auth0-spa-js' | |
import { computed, reactive, watchEffect } from 'vue' | |
let client | |
const state = reactive({ | |
loading: true, | |
isAuthenticated: false, | |
user: {}, | |
popupOpen: false, | |
error: null, | |
}) | |
/** | |
* Authenticates the user using a popup window | |
* | |
* @param {Object} o | |
*/ | |
async function loginWithPopup() { | |
state.popupOpen = true | |
try { | |
await client.loginWithPopup(0) | |
} catch (e) { | |
console.error(e) | |
} finally { | |
state.popupOpen = false | |
} | |
state.user = await client.getUser() | |
state.isAuthenticated = true | |
} | |
/** | |
* Handles the callback when logging in using a redirect | |
* | |
* @param {Object} o | |
*/ | |
async function handleRedirectCallback() { | |
state.loading = true | |
try { | |
await client.handleRedirectCallback() | |
state.user = await client.getUser() | |
state.isAuthenticated = true | |
} catch (e) { | |
state.error = e | |
} finally { | |
state.loading = false | |
} | |
} | |
/** | |
* Authenticates the user using the redirect method | |
* | |
* @param {Object} o | |
*/ | |
function loginWithRedirect(o) { | |
return client.loginWithRedirect(o) | |
} | |
/** | |
* Returns all the claims present in the ID token | |
* | |
* @param {Object} o | |
*/ | |
function getIdTokenClaims(o) { | |
return client.getIdTokenClaims(o) | |
} | |
/** | |
* Returns the access token. If the token is invalid or missing, | |
* a new one is retrieved | |
* | |
* @param {Object} o | |
*/ | |
function getTokenSilently(o) { | |
return client.getTokenSilently(o) | |
} | |
/** | |
* Gets the access token using a popup window | |
* | |
* @param {Object} o | |
*/ | |
function getTokenWithPopup(o) { | |
return client.getTokenWithPopup(o) | |
} | |
/** | |
* Logs the user out and removes their session on the authorization server | |
* | |
* @param {Object} o | |
*/ | |
function logout(o) { | |
return client.logout(o) | |
} | |
const authPlugin = { | |
isAuthenticated: computed(() => state.isAuthenticated), | |
loading: computed(() => state.loading), | |
user: computed(() => state.user), | |
getIdTokenClaims, | |
getTokenSilently, | |
getTokenWithPopup, | |
handleRedirectCallback, | |
loginWithRedirect, | |
loginWithPopup, | |
logout, | |
} | |
/** | |
* Authorization guard to protect routes in our app from unauthorized users | |
* | |
* @param {*} to | |
* @param {*} from | |
* @param {*} next | |
*/ | |
const routeGuard = (to, from, next) => { | |
const { isAuthenticated, loading, loginWithRedirect } = authPlugin | |
const verify = () => { | |
// If the user is authenticated, continue with the route | |
if (isAuthenticated.value) { | |
return next() | |
} | |
// Otherwise, log in | |
loginWithRedirect({ appState: { targetUrl: to.fullPath } }) | |
} | |
// If loading has already finished, check our auth state using `fn()` | |
if (!loading.value) { | |
return verify() | |
} | |
// Watch for the loading property to change before we check isAuthenticated | |
watchEffect(() => { | |
if (loading.value === false) { | |
return verify() | |
} | |
}) | |
} | |
async function init(options) { | |
const { onRedirectCallback, redirectUri = window.location.origin } = options | |
client = await createAuth0Client({ | |
domain: process.env.VUE_APP_AUTH0_DOMAIN, | |
client_id: process.env.VUE_APP_AUTH0_CLIENT_KEY, | |
audience: options.audience, | |
redirect_uri: redirectUri, | |
}) | |
try { | |
// If the user is returning to the app after authentication | |
if ( | |
window.location.search.includes('code=') && | |
window.location.search.includes('state=') | |
) { | |
// handle the redirect and retrieve tokens | |
const { appState } = await client.handleRedirectCallback() | |
// Notify subscribers that the redirect callback has happened, passing the appState | |
// (useful for retrieving any pre-authentication state) | |
onRedirectCallback(appState) | |
} | |
} catch (e) { | |
state.error = e | |
} finally { | |
// Initialize our internal authentication state | |
state.isAuthenticated = await client.isAuthenticated() | |
state.user = await client.getUser() | |
state.loading = false | |
} | |
return { | |
install: (app) => { | |
app.provide('Auth', authPlugin) | |
}, | |
} | |
} | |
export default { | |
init, | |
routeGuard, | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createApp } from 'vue' | |
import App from './App.vue' | |
import Auth from './plugins/auth0' | |
import router from './router' | |
async function init() { | |
const AuthPlugin = await Auth.init({ | |
onRedirectCallback: (appState) => { | |
router.push( | |
appState && appState.targetUrl | |
? appState.targetUrl | |
: window.location.pathname, | |
) | |
}, | |
}) | |
createApp(App).use(AuthPlugin).use(router).mount('#app') | |
} | |
init() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createRouter, createWebHistory } from 'vue-router' | |
import Auth from '../plugins/auth0' | |
import Home from '../views/Home.vue' | |
const routes = [ | |
{ | |
path: '/', | |
name: 'Home', | |
component: Home, | |
}, | |
{ | |
path: '/profile', | |
name: 'Profile', | |
beforeEnter: Auth.routeGuard, | |
component: () => | |
import(/* webpackChunkName: "profile" */ '../views/Profile.vue'), | |
}, | |
] | |
const router = createRouter({ | |
history: createWebHistory(process.env.BASE_URL), | |
routes, | |
}) | |
export default router |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's a sightly modified TS version that reads a
meta.requiresAuth
flag in the router instead of definingbeforeEnter
on each route if we pass a generalbeforeEnter: Auth.routeGuard
to thecreateRouter
options: