Skip to content

Commit afb55fd

Browse files
feat: anonymous user authentication
instead of using a single global api key for apps, anonymous sessions are used for getting a temporary access
1 parent b952b49 commit afb55fd

File tree

5 files changed

+103
-14
lines changed

5 files changed

+103
-14
lines changed

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"@babel/preset-env": "^7.15.8",
4242
"@maphubs/tokml": "^0.6.0",
4343
"@popperjs/core": "^2.4.0",
44+
"appwrite": "^15.0.0",
4445
"autoprefixer": "^7.1.2",
4546
"babel-core": "^7.0.0-bridge.0",
4647
"babel-loader": "^8.1.0",

pnpm-lock.yaml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app-loader.js

+8-14
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import I18nBuilder from '@/i18n/i18n-builder'
66
import constants from '@/resources/constants'
77
import appConfig from '@/config/app-config'
88
import AppHooks from '@/support/app-hooks'
9-
import {HttpClient} from 'vue-rest-client'
109
import utils from '@/support/utils'
1110
import store from '@/store/store'
1211
import router from '@/router'
1312
import lodash from 'lodash'
1413
import Vue from 'vue'
14+
import {getKeyObject} from '@/support/appwrite-utils'
1515

1616
class AppLoader {
1717
constructor() {
@@ -53,22 +53,16 @@ class AppLoader {
5353
}
5454
this.setInitialSettings(appConfig.orsApiKey, constants.endpoints)
5555
} else {
56-
const httpClient = new HttpClient({baseURL: appConfig.dataServiceBaseUrl})
57-
5856
try {
59-
// Request the public API key from the remote service
60-
// (only works when running the app on valid ORS domains).
61-
const response = await httpClient.http.get(appConfig.publicApiKeyUrl)
62-
this.setInitialSettings(response.data, constants.publicEndpoints)
63-
return response.data
57+
let key_object = await getKeyObject()
58+
this.setInitialSettings(key_object['key'], constants.publicEndpoints)
6459
} catch (error) {
65-
// If the request fails, use the local user key instead
66-
if (ORSKEY && ORSKEY !== 'put-an-ors-key-here' && ORSKEY !== '') {
67-
appConfig.orsApiKey = ORSKEY
68-
}
69-
this.setInitialSettings(appConfig.orsApiKey, constants.endpoints)
70-
console.log('Error acquiring api key:', error)
60+
console.log(error.code)
61+
console.log(error.type)
62+
console.log(error.message)
63+
throw error
7164
}
65+
7266
}
7367
}
7468
}

src/config-examples/app-config-example.js

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ const appConfig = {
2626
defaultLocale: 'en-us', // only set as default a locale that is present in the app. By default, they are: 'en-us', 'de-de' and 'pt-br'
2727
orsApiKey: 'put-here-an-ors-api-key', // ORS API key to be used on the ORS requests. You can get one here: https://openrouteservice.org/dev/#/signup
2828
useUserKey: true, // If the app is using a user ORS API key. // Don't change this unless you know what your doing!
29+
appwrite: { // used for HeiGIT apps
30+
endpoint: '',
31+
projectId: '',
32+
policy: '',
33+
linkAnonFunctionId: ''
34+
},
2935
bitlyApiKey: 'put-the-bitly-api-key-here', // Bit.ly key used to generate the short url
3036
bitlyLogin: 'put-the-bitly-login-here', // Bit.ly login used to generate the short url
3137

src/support/appwrite-utils.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// eslint-disable-next-line no-unused-vars
2+
import {Account, Client, Databases, Functions, Models, AppwriteException} from 'appwrite'
3+
import config from '@/config/app-config'
4+
5+
/**
6+
* Returns a Promise including an object with a 'tyk_api_key' property
7+
* @returns {Promise<Models.Document|any|undefined>}
8+
*/
9+
export const getKeyObject = async () => {
10+
const client = new Client()
11+
.setEndpoint(config.appwrite.endpoint) // move to config
12+
.setProject(config.appwrite.projectId) // move to config
13+
14+
const account = new Account(client)
15+
try {
16+
return await getExistingUserSession(account, client)
17+
} catch (error) {
18+
if (error.code === 401 && error.type === 'general_unauthorized_scope') {
19+
console.log('No existing Account')
20+
return await creatNewAnonUser(account, client)
21+
} else {
22+
throw error
23+
}
24+
}
25+
}
26+
27+
/**
28+
* Returns an existing anonymous user session
29+
* @param account
30+
* @param client
31+
* @returns {Promise<Models.Document>}
32+
* @throws AppwriteException
33+
*/
34+
const getExistingUserSession = async (account, client) => {
35+
const currentUser = await account.get()
36+
const databases = new Databases(client)
37+
return await databases.getDocument(
38+
'tyk_integration',
39+
'anonymous_keys',
40+
currentUser.$id
41+
)
42+
}
43+
44+
/**
45+
* Runs the appwrite function to link anon users
46+
* @param {Functions} functions
47+
*/
48+
function executeLinkAnonFunction(functions) {
49+
return functions.createExecution(
50+
config.appwrite.linkAnonFunctionId,
51+
JSON.stringify({
52+
tag: window.location.origin,
53+
policy: config.appwrite.policy
54+
}),
55+
)
56+
}
57+
58+
/**
59+
* Creates a new anonymous user & session.
60+
* Passes domain & configured policy to specific appwrite function
61+
* @param account
62+
* @param client
63+
* @returns {Promise<any>}
64+
*/
65+
const creatNewAnonUser = async (account, client) => {
66+
try {
67+
await account.createAnonymousSession()
68+
const functions = new Functions(client)
69+
70+
let res = await executeLinkAnonFunction(functions)
71+
72+
if (res.status === 'failed' && res.responseStatusCode === 500) {
73+
res = await executeLinkAnonFunction(functions)
74+
}
75+
return JSON.parse(res.responseBody)
76+
} catch (error) {
77+
console.error('Error creating anonymous user: ', error)
78+
throw error
79+
}
80+
}

0 commit comments

Comments
 (0)