BBIO-46 WIP
This commit is contained in:
parent
2b7a127701
commit
3c30049dc2
@ -1,5 +1,5 @@
|
|||||||
--
|
--
|
||||||
-- Generated by basebox compiler (bbc) version 0.1.0-beta.23 at 2023-10-31 15:13:34+01:00
|
-- Generated by basebox compiler (bbc) version 0.1.0-beta.23 at 2023-11-01 03:18:33+01:00
|
||||||
--
|
--
|
||||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Generated by bbc (basebox compiler) version 0.1.0-beta.23 at 2023-10-31 15:13:34+01:00
|
# Generated by bbc (basebox compiler) version 0.1.0-beta.23 at 2023-11-01 03:18:33+01:00
|
||||||
#
|
#
|
||||||
[resolvers.updateTask]
|
[resolvers.updateTask]
|
||||||
operation_name = "updateTask"
|
operation_name = "updateTask"
|
||||||
@ -36,6 +36,138 @@ column = "id"
|
|||||||
condition_str = "= '$id'"
|
condition_str = "= '$id'"
|
||||||
index = ""
|
index = ""
|
||||||
|
|
||||||
|
[resolvers.getUser]
|
||||||
|
operation_name = "getUser"
|
||||||
|
|
||||||
|
[resolvers.getUser.resolver.QueryBuilder]
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
|
||||||
|
[resolvers.getUser.resolver.QueryBuilder.command]
|
||||||
|
table = "User"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
columns = []
|
||||||
|
modify_values = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers.getUser.resolver.QueryBuilder.command.where_clauses]]
|
||||||
|
table = "User"
|
||||||
|
column = "username"
|
||||||
|
condition_str = "= '$username'"
|
||||||
|
index = ""
|
||||||
|
|
||||||
|
[resolvers.deleteTask]
|
||||||
|
operation_name = "deleteTask"
|
||||||
|
|
||||||
|
[resolvers.deleteTask.resolver.QueryBuilder]
|
||||||
|
command_type = "SQLDelete"
|
||||||
|
|
||||||
|
[resolvers.deleteTask.resolver.QueryBuilder.command]
|
||||||
|
table = "Task"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
columns = []
|
||||||
|
modify_values = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers.deleteTask.resolver.QueryBuilder.command.where_clauses]]
|
||||||
|
table = "Task"
|
||||||
|
column = "id"
|
||||||
|
condition_str = "= '$id'"
|
||||||
|
index = ""
|
||||||
|
|
||||||
|
[resolvers.createUser]
|
||||||
|
operation_name = "createUser"
|
||||||
|
|
||||||
|
[resolvers.createUser.resolver.QueryBuilder]
|
||||||
|
command_type = "SQLInsert"
|
||||||
|
|
||||||
|
[resolvers.createUser.resolver.QueryBuilder.command]
|
||||||
|
table = "User"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
columns = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
where_clauses = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]]
|
||||||
|
column = "username"
|
||||||
|
value = "'$username'"
|
||||||
|
|
||||||
|
[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]]
|
||||||
|
column = "name"
|
||||||
|
value = "'$name'"
|
||||||
|
|
||||||
|
[resolvers.createList]
|
||||||
|
operation_name = "createList"
|
||||||
|
|
||||||
|
[resolvers.createList.resolver.QueryBuilder]
|
||||||
|
command_type = "SQLInsert"
|
||||||
|
|
||||||
|
[resolvers.createList.resolver.QueryBuilder.command]
|
||||||
|
table = "List"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
columns = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
where_clauses = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers.createList.resolver.QueryBuilder.command.modify_values]]
|
||||||
|
column = "title"
|
||||||
|
value = "'$title'"
|
||||||
|
|
||||||
|
[[resolvers.createList.resolver.QueryBuilder.command.modify_values]]
|
||||||
|
column = "user_username"
|
||||||
|
value = "'$user.$username'"
|
||||||
|
|
||||||
|
[resolvers.updateList]
|
||||||
|
operation_name = "updateList"
|
||||||
|
|
||||||
|
[resolvers.updateList.resolver.QueryBuilder]
|
||||||
|
command_type = "SQLUpdate"
|
||||||
|
|
||||||
|
[resolvers.updateList.resolver.QueryBuilder.command]
|
||||||
|
table = "List"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
columns = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers.updateList.resolver.QueryBuilder.command.modify_values]]
|
||||||
|
column = "title"
|
||||||
|
value = "'$title'"
|
||||||
|
|
||||||
|
[[resolvers.updateList.resolver.QueryBuilder.command.where_clauses]]
|
||||||
|
table = "List"
|
||||||
|
column = "id"
|
||||||
|
condition_str = "= '$id'"
|
||||||
|
index = ""
|
||||||
|
|
||||||
|
[resolvers._bb_user_User]
|
||||||
|
operation_name = "_bb_user_User"
|
||||||
|
|
||||||
|
[resolvers._bb_user_User.resolver.InternalQueryBuilder]
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
|
||||||
|
[resolvers._bb_user_User.resolver.InternalQueryBuilder.command]
|
||||||
|
table = "User"
|
||||||
|
command_type = "SQLSelect"
|
||||||
|
modify_values = []
|
||||||
|
nested_modify_tables = []
|
||||||
|
aggregate_result = true
|
||||||
|
|
||||||
|
[[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.columns]]
|
||||||
|
|
||||||
|
[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.columns.Column]
|
||||||
|
table = "User"
|
||||||
|
column = "username"
|
||||||
|
|
||||||
|
[[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.where_clauses]]
|
||||||
|
table = "User"
|
||||||
|
column = ".ownerId"
|
||||||
|
condition_str = "= $1"
|
||||||
|
index = ""
|
||||||
|
|
||||||
[resolvers.createTask]
|
[resolvers.createTask]
|
||||||
operation_name = "createTask"
|
operation_name = "createTask"
|
||||||
|
|
||||||
@ -70,49 +202,6 @@ value = "'$list.$id'"
|
|||||||
column = "user_username"
|
column = "user_username"
|
||||||
value = "'$user.$username'"
|
value = "'$user.$username'"
|
||||||
|
|
||||||
[resolvers.updateList]
|
|
||||||
operation_name = "updateList"
|
|
||||||
|
|
||||||
[resolvers.updateList.resolver.QueryBuilder]
|
|
||||||
command_type = "SQLUpdate"
|
|
||||||
|
|
||||||
[resolvers.updateList.resolver.QueryBuilder.command]
|
|
||||||
table = "List"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
columns = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers.updateList.resolver.QueryBuilder.command.modify_values]]
|
|
||||||
column = "title"
|
|
||||||
value = "'$title'"
|
|
||||||
|
|
||||||
[[resolvers.updateList.resolver.QueryBuilder.command.where_clauses]]
|
|
||||||
table = "List"
|
|
||||||
column = "id"
|
|
||||||
condition_str = "= '$id'"
|
|
||||||
index = ""
|
|
||||||
|
|
||||||
[resolvers.deleteTask]
|
|
||||||
operation_name = "deleteTask"
|
|
||||||
|
|
||||||
[resolvers.deleteTask.resolver.QueryBuilder]
|
|
||||||
command_type = "SQLDelete"
|
|
||||||
|
|
||||||
[resolvers.deleteTask.resolver.QueryBuilder.command]
|
|
||||||
table = "Task"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
columns = []
|
|
||||||
modify_values = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers.deleteTask.resolver.QueryBuilder.command.where_clauses]]
|
|
||||||
table = "Task"
|
|
||||||
column = "id"
|
|
||||||
condition_str = "= '$id'"
|
|
||||||
index = ""
|
|
||||||
|
|
||||||
[resolvers.deleteList]
|
[resolvers.deleteList]
|
||||||
operation_name = "deleteList"
|
operation_name = "deleteList"
|
||||||
|
|
||||||
@ -132,92 +221,3 @@ table = "List"
|
|||||||
column = "id"
|
column = "id"
|
||||||
condition_str = "= '$id'"
|
condition_str = "= '$id'"
|
||||||
index = ""
|
index = ""
|
||||||
|
|
||||||
[resolvers.createUser]
|
|
||||||
operation_name = "createUser"
|
|
||||||
|
|
||||||
[resolvers.createUser.resolver.QueryBuilder]
|
|
||||||
command_type = "SQLInsert"
|
|
||||||
|
|
||||||
[resolvers.createUser.resolver.QueryBuilder.command]
|
|
||||||
table = "User"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
columns = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
where_clauses = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]]
|
|
||||||
column = "username"
|
|
||||||
value = "'$username'"
|
|
||||||
|
|
||||||
[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]]
|
|
||||||
column = "name"
|
|
||||||
value = "'$name'"
|
|
||||||
|
|
||||||
[resolvers._bb_user_User]
|
|
||||||
operation_name = "_bb_user_User"
|
|
||||||
|
|
||||||
[resolvers._bb_user_User.resolver.InternalQueryBuilder]
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
|
|
||||||
[resolvers._bb_user_User.resolver.InternalQueryBuilder.command]
|
|
||||||
table = "User"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
modify_values = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.columns]]
|
|
||||||
|
|
||||||
[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.columns.Column]
|
|
||||||
table = "User"
|
|
||||||
column = "username"
|
|
||||||
|
|
||||||
[[resolvers._bb_user_User.resolver.InternalQueryBuilder.command.where_clauses]]
|
|
||||||
table = "User"
|
|
||||||
column = ".ownerId"
|
|
||||||
condition_str = "= $1"
|
|
||||||
index = ""
|
|
||||||
|
|
||||||
[resolvers.createList]
|
|
||||||
operation_name = "createList"
|
|
||||||
|
|
||||||
[resolvers.createList.resolver.QueryBuilder]
|
|
||||||
command_type = "SQLInsert"
|
|
||||||
|
|
||||||
[resolvers.createList.resolver.QueryBuilder.command]
|
|
||||||
table = "List"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
columns = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
where_clauses = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers.createList.resolver.QueryBuilder.command.modify_values]]
|
|
||||||
column = "title"
|
|
||||||
value = "'$title'"
|
|
||||||
|
|
||||||
[[resolvers.createList.resolver.QueryBuilder.command.modify_values]]
|
|
||||||
column = "user_username"
|
|
||||||
value = "'$user.$username'"
|
|
||||||
|
|
||||||
[resolvers.getUser]
|
|
||||||
operation_name = "getUser"
|
|
||||||
|
|
||||||
[resolvers.getUser.resolver.QueryBuilder]
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
|
|
||||||
[resolvers.getUser.resolver.QueryBuilder.command]
|
|
||||||
table = "User"
|
|
||||||
command_type = "SQLSelect"
|
|
||||||
columns = []
|
|
||||||
modify_values = []
|
|
||||||
nested_modify_tables = []
|
|
||||||
aggregate_result = true
|
|
||||||
|
|
||||||
[[resolvers.getUser.resolver.QueryBuilder.command.where_clauses]]
|
|
||||||
table = "User"
|
|
||||||
column = "username"
|
|
||||||
condition_str = "= '$username'"
|
|
||||||
index = ""
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { RouterLink, RouterView } from 'vue-router'
|
import { RouterLink, RouterView } from 'vue-router'
|
||||||
import { store } from './store.js'
|
import { store, loggedIn } from './store.js'
|
||||||
import {clearSession} from "./store.js";
|
import {clearSession} from "./store.js";
|
||||||
import {Modal} from "bootstrap";
|
import {Modal} from "bootstrap";
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ function dismissError() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- navigation items are shown only if logged in -->
|
<!-- navigation items are shown only if logged in -->
|
||||||
<div v-if="$oidc.isAuthenticated" class="collapse navbar-collapse" id="navbarSupportedContent">
|
<div v-if="loggedIn()" class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<RouterLink to="/" class="nav-link" active-class="active">Tasks</RouterLink>
|
<RouterLink to="/" class="nav-link" active-class="active">Tasks</RouterLink>
|
||||||
|
12
src/components/auth/Callback.vue
Normal file
12
src/components/auth/Callback.vue
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
console.log('Component is mounted!');
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
0
src/components/auth/Login.vue
Normal file
0
src/components/auth/Login.vue
Normal file
@ -1,80 +0,0 @@
|
|||||||
/**
|
|
||||||
* Configure oidc-client library.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Oidc from 'oidc-client';
|
|
||||||
|
|
||||||
Oidc.Log.logger = console;
|
|
||||||
Oidc.Log.level = (process.env.NODE_ENV === 'production') ? Oidc.Log.ERROR : Oidc.Log.DEBUG;
|
|
||||||
|
|
||||||
// OIDC configuration
|
|
||||||
let oidcProviderDomain = 'https://basebox-test-1.eu.auth0.com';
|
|
||||||
let clientId = '5wl8hQV1thh07rScSoJ3aN56ETuXWprg';
|
|
||||||
let scopes = "openid profile email"
|
|
||||||
|
|
||||||
let instance;
|
|
||||||
|
|
||||||
// OIDC Client
|
|
||||||
export const getOidcClient = () => {
|
|
||||||
if (instance) {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance = new Oidc.UserManager({
|
|
||||||
userStore: new Oidc.WebStorageStateStore(),
|
|
||||||
authority: oidcProviderDomain,
|
|
||||||
client_id: clientId,
|
|
||||||
redirect_uri: window.location.origin + '/callback',
|
|
||||||
response_type: 'code',
|
|
||||||
scope: scopes,
|
|
||||||
post_logout_redirect_uri: window.location.origin + '/home?action=logout',
|
|
||||||
accessTokenExpiringNotificationTime: 10,
|
|
||||||
automaticSilentRenew: false,
|
|
||||||
filterProtocolClaims: false,
|
|
||||||
loadUserInfo: true,
|
|
||||||
includeIdTokenInSilentRenew: false
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.events.addAccessTokenExpiring(function() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('access token expiring')
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addAccessTokenExpired(function() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('access token expired')
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addSilentRenewError(function(err) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error('silent renew error', err)
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addUserLoaded(function(user) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('user loaded', user)
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addUserSignedIn(function(user) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('user signed in', user)
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addUserUnloaded(function() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('user unloaded')
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addUserSignedOut(function() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('user signed out')
|
|
||||||
})
|
|
||||||
|
|
||||||
instance.events.addUserSessionChanged(function() {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log('user session changed')
|
|
||||||
})
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
@ -9,8 +9,7 @@ import {loggedIn, showError, store} from "../store";
|
|||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import HomeView from '../views/HomeView.vue'
|
import HomeView from '../views/HomeView.vue'
|
||||||
import { objectToQueryString } from "../util/net";
|
import { objectToQueryString } from "../util/net";
|
||||||
import {oauthCallbackHandler} from "../util/oauth";
|
import { callbackPath, getOidcUserManager } from "../util/oidc";
|
||||||
import {storeInit} from "../store";
|
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
history: createWebHistory(import.meta.env.BASE_URL),
|
||||||
@ -38,24 +37,18 @@ const router = createRouter({
|
|||||||
|
|
||||||
router.beforeEach(async (to, from) => {
|
router.beforeEach(async (to, from) => {
|
||||||
|
|
||||||
// Handle OAuth callback request.
|
/* catch OIDC callback */
|
||||||
// This request is coming in after the user entered her/his credentials at the IdP
|
if (to.path === callbackPath) {
|
||||||
// login form; the IdP (e.g. Keycloak) redirects the browser to the URL of this route.
|
const userMgr = getOidcUserManager();
|
||||||
if (to.path.startsWith("/oauth-callback")) {
|
|
||||||
let queryString = objectToQueryString(to.query);
|
|
||||||
console.info(`Got /oauth-callback with query string '${queryString}`);
|
|
||||||
|
|
||||||
/* Pass the query string to the handler function */
|
|
||||||
try {
|
try {
|
||||||
await oauthCallbackHandler(queryString);
|
const user = await userMgr.signinRedirectCallback();
|
||||||
|
console.log("OIDC: login complete, user: ", user);
|
||||||
|
storeInit(user);
|
||||||
|
/* redirect to home page */
|
||||||
|
return {name: 'home'};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const errorMsg = `Failed to get session info from basebox/finish OpenID Connect login: ${err}`;
|
console.error("OIDC: login failed: ", err);
|
||||||
console.error(errorMsg);
|
|
||||||
/* show error */
|
|
||||||
showError(errorMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {name: 'home'};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if no user is logged in, we redirect to the home page */
|
/* if no user is logged in, we redirect to the home page */
|
||||||
|
29
src/store.js
29
src/store.js
@ -18,8 +18,8 @@ export const store = reactive({
|
|||||||
/** base URL of basebox broker host */
|
/** base URL of basebox broker host */
|
||||||
baseboxHost: import.meta.env.BASEBOX_HOST || "http://127.0.0.1:8080",
|
baseboxHost: import.meta.env.BASEBOX_HOST || "http://127.0.0.1:8080",
|
||||||
|
|
||||||
/** basebox session data */
|
/** User as returned from oidc-client */
|
||||||
session: {},
|
user: null,
|
||||||
|
|
||||||
/** Fatal error message, if any */
|
/** Fatal error message, if any */
|
||||||
fatalError: "",
|
fatalError: "",
|
||||||
@ -35,14 +35,15 @@ export const store = reactive({
|
|||||||
* Return true if the user is logged in.
|
* Return true if the user is logged in.
|
||||||
*/
|
*/
|
||||||
export function loggedIn() {
|
export function loggedIn() {
|
||||||
return store.session && store.session.token;
|
return store.user !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear session data.
|
* Clear session data.
|
||||||
*/
|
*/
|
||||||
export function clearSession() {
|
export function clearSession() {
|
||||||
store.session = {};
|
store.user = null;
|
||||||
|
store.userDisplayName = "stranger";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,27 +70,17 @@ export function clearError() {
|
|||||||
*
|
*
|
||||||
* Additionally, we also create the default list here and save everything in the store.
|
* Additionally, we also create the default list here and save everything in the store.
|
||||||
*
|
*
|
||||||
* @param session - the session info as returned by the OpenID Connect login.
|
* @param user - the user as returned from oidc-client.
|
||||||
*/
|
*/
|
||||||
export async function storeInit(session) {
|
export async function storeInit(user) {
|
||||||
|
|
||||||
/* save user session in the store */
|
/* save user session in the store */
|
||||||
store.session = { ...session };
|
store.user = user;
|
||||||
|
|
||||||
/* The information in the session object depends on the OpenID Connect provider.
|
store.userDisplayName = user.profile.nickname || "Logged In Stranger";
|
||||||
* The following fields are always present:
|
|
||||||
*
|
|
||||||
* `token` - basebox session token
|
|
||||||
* `subject` - unique user id (not a username, rather a number or UUID)
|
|
||||||
* `id_token_claims` - all fields found in the ID token.
|
|
||||||
*
|
|
||||||
* Since we assume Auth0 being the Open ID Connect provider, we use `id_token_claims.nickname`
|
|
||||||
* as the user name we display in the UI.
|
|
||||||
*/
|
|
||||||
store.userDisplayName = session.id_token_claims.nickname;
|
|
||||||
|
|
||||||
/* The unique user ID is the 'sub' field from the ID token. */
|
/* The unique user ID is the 'sub' field from the ID token. */
|
||||||
store.userId = session.subject;
|
store.userId = user.profile.sub;
|
||||||
|
|
||||||
/* Create user and default list.
|
/* Create user and default list.
|
||||||
* We cannot run these requests in parallel, since the user record must exist in the database
|
* We cannot run these requests in parallel, since the user record must exist in the database
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
/**
|
|
||||||
* OAuth specific functions.
|
|
||||||
*
|
|
||||||
* Part of the basebox sample Todo app.
|
|
||||||
* https://basebox.io
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {store} from "../store";
|
|
||||||
import {storeInit} from "../store";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle OAuth callback and complete login process.
|
|
||||||
*
|
|
||||||
* After the user enters her/his credentials at the IdP (Keycloak) login form, she/he
|
|
||||||
* gets redirected to a client URL; this function handles this request.
|
|
||||||
*
|
|
||||||
* This function passes the query string received with the callback to the basebox broker,
|
|
||||||
* which responds with a session information struct (JSON) like this:
|
|
||||||
*
|
|
||||||
* {
|
|
||||||
* "token":"47caa9df-ac89-45a8-8b22-9c0925d6aed0",
|
|
||||||
* "username":"tester",
|
|
||||||
* "first_name":"Fred",
|
|
||||||
* "last_name":"Feuerstein",
|
|
||||||
* "roles":[
|
|
||||||
* "/user"
|
|
||||||
* ],
|
|
||||||
* "claims":{
|
|
||||||
* "groups":[
|
|
||||||
* "/user"
|
|
||||||
* ]
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* The session is then stored in app state.
|
|
||||||
*
|
|
||||||
* Then, this function checks if the user is known in the database; since we use Keycloak/OpenID Connect
|
|
||||||
* for user management, the user might be available in Keycloak, but not in the database. So if the user
|
|
||||||
* is not there, it is created.
|
|
||||||
*
|
|
||||||
* @param queryString
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
* @throws Error if the session data cannot be retrieved.
|
|
||||||
*/
|
|
||||||
export async function oauthCallbackHandler(queryString) {
|
|
||||||
|
|
||||||
/* Pass query string to the broker to complete the login process. */
|
|
||||||
const response = await fetch(`${store.baseboxHost}/oauth/complete-login?${queryString}`, {
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error("Failed to get session data: " + response.statusText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store session data and initialize data store. */
|
|
||||||
const rspJson = await response.json();
|
|
||||||
await storeInit(rspJson);
|
|
||||||
}
|
|
74
src/util/oidc.js
Normal file
74
src/util/oidc.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Configure oidc-client-ts library and retrieve UserManager instance for authentication.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Log, UserManager, WebStorageStateStore } from 'oidc-client-ts';
|
||||||
|
|
||||||
|
Log.logger = console;
|
||||||
|
Log.level = (process.env.NODE_ENV === 'production') ? Log.ERROR : Log.DEBUG;
|
||||||
|
|
||||||
|
// OIDC configuration
|
||||||
|
const oidcProviderDomain = 'https://basebox-test-1.eu.auth0.com';
|
||||||
|
const clientId = '5wl8hQV1thh07rScSoJ3aN56ETuXWprg';
|
||||||
|
const scopes = "openid profile email";
|
||||||
|
export const callbackPath = "/auth/callback"
|
||||||
|
|
||||||
|
/* OIDC UserManager singleton */
|
||||||
|
let userMgr = null;
|
||||||
|
|
||||||
|
// OIDC Client
|
||||||
|
export const getOidcUserManager = () => {
|
||||||
|
if (userMgr) {
|
||||||
|
return userMgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
userMgr = new UserManager({
|
||||||
|
userStore: new WebStorageStateStore(),
|
||||||
|
authority: oidcProviderDomain,
|
||||||
|
client_id: clientId,
|
||||||
|
redirect_uri: window.location.origin + callbackPath,
|
||||||
|
response_type: 'code',
|
||||||
|
scope: scopes,
|
||||||
|
post_logout_redirect_uri: window.location.origin + '/home?action=logout',
|
||||||
|
accessTokenExpiringNotificationTime: 10,
|
||||||
|
automaticSilentRenew: false,
|
||||||
|
filterProtocolClaims: false,
|
||||||
|
loadUserInfo: true,
|
||||||
|
includeIdTokenInSilentRenew: false
|
||||||
|
});
|
||||||
|
|
||||||
|
userMgr.events.addAccessTokenExpiring(function() {
|
||||||
|
console.info('OIDC: access token expiring')
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addAccessTokenExpired(function() {
|
||||||
|
console.info('OIDC: access token expired')
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addSilentRenewError(function(err) {
|
||||||
|
console.error('silent renew error', err)
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addUserLoaded(function(user) {
|
||||||
|
console.info('OIDC: user loaded', user)
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addUserSignedIn(function(user) {
|
||||||
|
console.info('OIDC: user signed in', user)
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addUserUnloaded(function() {
|
||||||
|
console.info('OIDC: user unloaded')
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addUserSignedOut(function() {
|
||||||
|
console.info('OIDC: user signed out')
|
||||||
|
})
|
||||||
|
|
||||||
|
userMgr.events.addUserSessionChanged(function() {
|
||||||
|
console.info('OIDC: user session changed')
|
||||||
|
})
|
||||||
|
|
||||||
|
return userMgr;
|
||||||
|
}
|
@ -9,6 +9,21 @@
|
|||||||
import { store } from "../store";
|
import { store } from "../store";
|
||||||
import {loggedIn} from "../store";
|
import {loggedIn} from "../store";
|
||||||
import TodoRoot from "../components/Todo.vue";
|
import TodoRoot from "../components/Todo.vue";
|
||||||
|
import { getOidcUserManager } from "../util/oidc";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start login process.
|
||||||
|
*/
|
||||||
|
function doLogin() {
|
||||||
|
console.log("doLogin");
|
||||||
|
const userMgr = getOidcUserManager();
|
||||||
|
userMgr.signinRedirect().then(() => {
|
||||||
|
console.log("signinRedirect");
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error("signinRedirect failed", err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -16,11 +31,11 @@ import TodoRoot from "../components/Todo.vue";
|
|||||||
<main>
|
<main>
|
||||||
|
|
||||||
<!-- Force user to log in before he/she can see tasks. -->
|
<!-- Force user to log in before he/she can see tasks. -->
|
||||||
<div v-if="!$oidc.isAuthenticated" id="login-prompt">
|
<div v-if="!loggedIn()" id="login-prompt">
|
||||||
<h1>Welcome to basebox' TODO sample app!</h1>
|
<h1>Welcome to basebox' TODO sample app!</h1>
|
||||||
|
|
||||||
<p class="mt-5">Your are currently not logged in.</p>
|
<p class="mt-5">Your are currently not logged in.</p>
|
||||||
<button class="btn btn-primary" @click="$oidc.signIn()" type="button">Login</button>
|
<button class="btn btn-primary" @click="doLogin()" type="button">Login</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TodoRoot v-if="loggedIn()" />
|
<TodoRoot v-if="loggedIn()" />
|
||||||
|
Loading…
Reference in New Issue
Block a user