diff --git a/.env b/.env new file mode 100644 index 0000000..9c80b2d --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +HOST=127.0.0.1 + diff --git a/README.md b/README.md index cc5b6ae..9e28253 100644 --- a/README.md +++ b/README.md @@ -13,14 +13,14 @@ Let's assume you create a `basebox` folder in your home directory, change into i cd ~ mkdir basebox cd basebox -tar xzf basebox-version.tgz # adopt this command to the archive you downloaded +tar xzf basebox-x.x.x.tgz # adopt this command to the archive you downloaded git clone --single-branch --depth 1 https://gitea.basebox.health/samples/vue-todo.git ``` The basebox archive will be extracted into a directory named `basebox-`; for the scripts in `vue-todo/bbconf` to find the basebox binaries, please create a symbolic link to the basebox directory named `basebox`, e.g. ``` sh -ln -s basebox-0.1.1-beta.1 basebox +ln -s basebox-x.x.x basebox ``` If you follow these steps, the scripts in `bbconf` will work out of the box. @@ -30,18 +30,15 @@ If you follow these steps, the scripts in `bbconf` will work out of the box. To install this app, you need * npm, node.js -* A PostgreSQL server, preferably on the local host (simpler, but not suitable for production) -* basebox components (broker, dbproxy, bbc) -* Keycloak +* A PostgreSQL server +* basebox (broker, dbproxy, bbc extracted from the basebox archive) +* Keycloak or Auth0 ### PostgreSQL Preparation > You need a PostgreSQL database to run this app. You can read detailed instructions on how to > install PostgreSQL and create a test database at our [PostgreSQL Primer](https://docs.basebox.io/getting-started/postgresql/) page. -The recommended way to run basebox is to have a dedicated Unix user for basebox that authenticates to PostgreSQL using Peer authentication. This way, no password for the DB user has to be stored anywhere. -However, to keep things simple for the test app, we create a local user that authenticates to the database server via password (md5). - Let's create a PostgreSQL user and database for the TODO app: ``` sh @@ -98,7 +95,7 @@ This will install the client app's dependencies. ### OpenID Connect -You can setup and or use your own OpenID Connect server; if you do so, you also have to update the config files `bbconf/broker-config.toml` and `bbconf/dbroxy-config.toml` accordingly. +You can setup and use your own OpenID Connect server; if you do so, you also have to update the config files `bbconf/broker-config.toml` and `bbconf/dbroxy-config.toml` accordingly. If you just want to try things out, you are welcome to use our development Keycloak server. The config files are already setup to use it. There is a test user named `tester`, the password is `rantanplan`. @@ -149,6 +146,4 @@ This will start a node.js based HTTP test server that will host the client appli ``` -**Important Note**: If the URL you are seeing uses *localhost*, you have to edit broker's config file accordingly. The value you have to change is `redirect_url`; replace "127.0.0.1" with "localhost". - Open your browser, go go the URL in the npm console, and enjoy. diff --git a/bbconf/bb_todo-datamodel.sql b/bbconf/bb_todo-datamodel.sql index d5f6796..c38a9e2 100644 --- a/bbconf/bb_todo-datamodel.sql +++ b/bbconf/bb_todo-datamodel.sql @@ -1,5 +1,5 @@ -- --- Generated by basebox compiler (bbc) version 0.1.0-beta.23 at 2023-10-30 16:54:43+01:00 +-- Generated by basebox compiler (bbc) version 0.1.0-beta.23 at 2023-10-31 15:13:34+01:00 -- CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/bbconf/bb_todo-resolver.toml b/bbconf/bb_todo-resolver.toml index 7709456..ce0f71a 100644 --- a/bbconf/bb_todo-resolver.toml +++ b/bbconf/bb_todo-resolver.toml @@ -1,147 +1,6 @@ # -# Generated by bbc (basebox compiler) version 0.1.0-beta.23 at 2023-10-30 16:54:43+01:00 +# Generated by bbc (basebox compiler) version 0.1.0-beta.23 at 2023-10-31 15:13:34+01:00 # -[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.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.createTask] -operation_name = "createTask" - -[resolvers.createTask.resolver.QueryBuilder] -command_type = "SQLInsert" - -[resolvers.createTask.resolver.QueryBuilder.command] -table = "Task" -command_type = "SQLSelect" -columns = [] -nested_modify_tables = [] -where_clauses = [] -aggregate_result = true - -[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] -column = "title" -value = "'$title'" - -[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] -column = "description" -value = "'$description'" - -[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] -column = "completed" -value = "'$completed'" - -[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] -column = "list_id" -value = "'$list.$id'" - -[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] -column = "user_username" -value = "'$user.$username'" - -[resolvers.deleteList] -operation_name = "deleteList" - -[resolvers.deleteList.resolver.QueryBuilder] -command_type = "SQLDelete" - -[resolvers.deleteList.resolver.QueryBuilder.command] -table = "List" -command_type = "SQLSelect" -columns = [] -modify_values = [] -nested_modify_tables = [] -aggregate_result = true - -[[resolvers.deleteList.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.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.updateTask] operation_name = "updateTask" @@ -177,27 +36,39 @@ column = "id" condition_str = "= '$id'" index = "" -[resolvers.createUser] -operation_name = "createUser" +[resolvers.createTask] +operation_name = "createTask" -[resolvers.createUser.resolver.QueryBuilder] +[resolvers.createTask.resolver.QueryBuilder] command_type = "SQLInsert" -[resolvers.createUser.resolver.QueryBuilder.command] -table = "User" +[resolvers.createTask.resolver.QueryBuilder.command] +table = "Task" command_type = "SQLSelect" columns = [] nested_modify_tables = [] where_clauses = [] aggregate_result = true -[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]] -column = "username" -value = "'$username'" +[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] +column = "title" +value = "'$title'" -[[resolvers.createUser.resolver.QueryBuilder.command.modify_values]] -column = "name" -value = "'$name'" +[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] +column = "description" +value = "'$description'" + +[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] +column = "completed" +value = "'$completed'" + +[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] +column = "list_id" +value = "'$list.$id'" + +[[resolvers.createTask.resolver.QueryBuilder.command.modify_values]] +column = "user_username" +value = "'$user.$username'" [resolvers.updateList] operation_name = "updateList" @@ -221,3 +92,132 @@ 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] +operation_name = "deleteList" + +[resolvers.deleteList.resolver.QueryBuilder] +command_type = "SQLDelete" + +[resolvers.deleteList.resolver.QueryBuilder.command] +table = "List" +command_type = "SQLSelect" +columns = [] +modify_values = [] +nested_modify_tables = [] +aggregate_result = true + +[[resolvers.deleteList.resolver.QueryBuilder.command.where_clauses]] +table = "List" +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._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 = "" diff --git a/bbconf/broker-config-access-token-mode.toml b/bbconf/broker-config-access-token-mode.toml deleted file mode 100644 index 099ca42..0000000 --- a/bbconf/broker-config-access-token-mode.toml +++ /dev/null @@ -1,50 +0,0 @@ -[generic] -# log level; can be error, warn, info, debug, trace -log_level = "trace" - -[graphql] -# path and file name to GraphQL schema file -schema_file = "todo_schema.graphql" -allow_introspection = true - -[proxy] -# host name or IP of basebox DB proxy -host = "localhost" -port = 8081 -# Whether to use http or https to connect to the proxy -tls = false - -[server] -# Host name of the broker (GraphQL server) -host = "192.168.2.172" - -# Port number; default is 80 for http, 443 for https -port = 8080 - -# number of HTTP server threads to spawn; default is one per CPU core -workers = 2 - -# Path and file name of TLS/SSL key file -# cert_key_file = "/path/to/key.pem" - -# Path and file name of TLS certificate (chain) file -# cert_file = "/path/to/cert.pem" - -[auth] -mode = "access-token" - -# Base URL to the identity provider (OAuth2/OpenID Connect server, e.g. Keycloak) -iss = "https://basebox-test-1.eu.auth0.com/" -aud = "basebox-todo" - - -[business_logic_layer] -business_logic_layer_enabled = false -python_module_path = "/path/to/python/module" -python_module_name = "mymodule" - -[business_logic_layer.pre_definition] -all = ["query"] -query = ["getExercises", "getExercise"] -mutation = ["createExercise", "updateExercise", "deleteExercise"] -fragment = [] diff --git a/bbconf/broker-config.toml b/bbconf/broker-config.toml index 0844c8c..ff0dbaa 100644 --- a/bbconf/broker-config.toml +++ b/bbconf/broker-config.toml @@ -31,52 +31,7 @@ workers = 2 # cert_file = "/path/to/cert.pem" [auth] -mode = "client" - -# OAuth2 client id -client_id = "5wl8hQV1thh07rScSoJ3aN56ETuXWprg" - -# OAuth2 client secret -client_secret = "QlHMvIffKLRviCcSu_bPQcf8e4dc6WeS3BwZE1r1F-9R30AFoeYEwaOazAuFenI5" - -# Base URL to the identity provider (OAuth2/OpenID Connect server, e.g. Keycloak) -idp_url = "https://basebox-test-1.eu.auth0.com" - -# OpenID Connect scope; default is "openid profile email" -scope = "openid profile email" - -# Fully qualified URL to the OAuth2 callback endpoint. -# After the user entered his/her credentials at the IdP's login form, the client will be redirected -# to this URL. When the client receives a request to this URL, it must send the request's query -# string to the broker's "openid_connect_path" set below. -redirect_url = "http://127.0.0.1:5173/oauth-callback" - -# OpenID Connect login completion request path. -# The client must pass the query string from the call to "redirect_url" to this URL and gets -# a basebox session token in return. -openid_connect_path = "/oauth/complete-login" - -# Path to the browser login URL. -# This path is where the basebox broker returns a 302 response that redirects the browser to -# the IdP login page; the target URL will contain all query parms needed to initiate an -# auth code flow login procedure, incl. CSRF protection tokens etc. -login_path = "/oauth/login" - -# Logout path that allows explicit, immediate logouts. -# Simply POST to this URL with the session cookie or bearer token. -logout_path = "/oauth/logout" - -# Set to true to get a user's additional claims from OAuth2 -user_info_additional_claims_required = true - - -[business_logic_layer] -business_logic_layer_enabled = false -python_module_path = "/path/to/python/module" -python_module_name = "mymodule" - -[business_logic_layer.pre_definition] -all = ["query"] -query = ["getExercises", "getExercise"] -mutation = ["createExercise", "updateExercise", "deleteExercise"] -fragment = [] +# Contents of 'iss' field, usually the URL of the authetnication realm +iss = "https://basebox-test-1.eu.auth0.com/" +# Access token audience field +aud = "basebox-todo" diff --git a/package-lock.json b/package-lock.json index 369e113..0c3aa3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@popperjs/core": "^2.11.6", "bootstrap": "^5.3.0-alpha1", "bootstrap-icons": "^1.10.3", + "oidc-client-ts": "^2.4.0", "vue": "^3.2.47", "vue-router": "^4.1.6" }, @@ -596,6 +597,11 @@ "fsevents": "~2.3.2" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/csstype": { "version": "2.6.21", "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", @@ -759,6 +765,11 @@ "node": ">=0.12.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "node_modules/magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -787,6 +798,18 @@ "node": ">=0.10.0" } }, + "node_modules/oidc-client-ts": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-2.4.0.tgz", + "integrity": "sha512-WijhkTrlXK2VvgGoakWJiBdfIsVGz6CFzgjNNqZU1hPKV2kyeEaJgLs7RwuiSp2WhLfWBQuLvr2SxVlZnk3N1w==", + "dependencies": { + "crypto-js": "^4.2.0", + "jwt-decode": "^3.1.2" + }, + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", diff --git a/package.json b/package.json index 6a77e89..9390efa 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@popperjs/core": "^2.11.6", "bootstrap": "^5.3.0-alpha1", "bootstrap-icons": "^1.10.3", + "oidc-client-ts": "^2.4.0", "vue": "^3.2.47", "vue-router": "^4.1.6" }, diff --git a/src/App.vue b/src/App.vue index 6e4b6c2..e86881c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -33,7 +33,7 @@ function dismissError() { -