mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-03-31 15:20:32 +08:00
feat: Next auth implementation work in progress.
This commit is contained in:
parent
9eb34c8700
commit
bf5692aed2
packages
build/src
engine/src/actions
plugins
actions/actions-core/src/actions
plugins/plugin-next-auth/src/auth
server/lib/utils/auth
@ -33,6 +33,9 @@ async function validateAuthConfig({ components }) {
|
||||
if (type.isNone(components.auth.pages.roles)) {
|
||||
components.auth.pages.roles = {};
|
||||
}
|
||||
if (type.isNone(components.auth.providers)) {
|
||||
components.auth.providers = [];
|
||||
}
|
||||
|
||||
const { valid } = validate({
|
||||
schema: lowdefySchema.definitions.authConfig,
|
||||
|
@ -216,6 +216,9 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
theme: {
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
},
|
||||
block: {
|
||||
|
@ -15,8 +15,8 @@
|
||||
*/
|
||||
|
||||
function createLogout({ context }) {
|
||||
return function logout() {
|
||||
return context._internal.lowdefy._internal.auth.logout();
|
||||
return function logout(params) {
|
||||
return context._internal.lowdefy._internal.auth.logout(params);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,6 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
test('Login action invocation', async () => {
|
||||
Login({ methods: { login: mockActionMethod }, params: 'call' });
|
||||
expect(mockActionMethod.mock.calls).toEqual([['call']]);
|
||||
Login({ methods: { login: mockActionMethod }, params: 'params' });
|
||||
expect(mockActionMethod.mock.calls).toEqual([['params']]);
|
||||
});
|
||||
|
@ -14,8 +14,8 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
function Logout({ methods: { logout } }) {
|
||||
return logout();
|
||||
function Logout({ methods: { logout }, params }) {
|
||||
return logout(params);
|
||||
}
|
||||
|
||||
export default Logout;
|
||||
|
@ -23,6 +23,6 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
test('Logout action invocation', async () => {
|
||||
Logout({ methods: { logout: mockActionMethod } });
|
||||
expect(mockActionMethod.mock.calls).toEqual([[]]);
|
||||
Logout({ methods: { logout: mockActionMethod }, params: 'params' });
|
||||
expect(mockActionMethod.mock.calls).toEqual([['params']]);
|
||||
});
|
||||
|
@ -14,5 +14,13 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
export { default as Auth0Provider } from 'next-auth/providers/auth0';
|
||||
export { default as GoogleProvider } from 'next-auth/providers/google';
|
||||
// This syntax does not work because next-auth is not an es module.
|
||||
// export { default as Auth0Provider } from 'next-auth/providers/auth0';
|
||||
|
||||
import _auth0 from 'next-auth/providers/auth0';
|
||||
import _google from 'next-auth/providers/google';
|
||||
|
||||
const Auth0Provider = _auth0.default;
|
||||
const GoogleProvider = _google.default;
|
||||
|
||||
export { Auth0Provider, GoogleProvider };
|
||||
|
51
packages/server/lib/utils/auth/getAuthMethods.js
Normal file
51
packages/server/lib/utils/auth/getAuthMethods.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { type, urlQuery as urlQueryFn } from '@lowdefy/helpers';
|
||||
import { signIn, signOut } from 'next-auth/react';
|
||||
|
||||
function getCallbackUrl({ lowdefy, callbackUrl = {} }) {
|
||||
const { home, pageId, urlQuery } = callbackUrl;
|
||||
|
||||
if ([!home, !pageId].filter((v) => !v).length > 1) {
|
||||
throw Error(`Invalid Link: To avoid ambiguity, only one of 'home' or 'pageId' can be defined.`);
|
||||
}
|
||||
const query = type.isNone(urlQuery) ? '' : `${urlQueryFn.stringify(urlQuery)}`;
|
||||
|
||||
if (home === true) {
|
||||
return `/${lowdefy.home.configured ? '' : lowdefy.home.pageId}${query ? `?${query}` : ''}`;
|
||||
}
|
||||
if (type.isString(pageId)) {
|
||||
return `/${pageId}${query ? `?${query}` : ''}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getAuthMethods({ lowdefy }) {
|
||||
function login({ providerId, callbackUrl, authUrl = {} }) {
|
||||
signIn(providerId, { callbackUrl: getCallbackUrl({ lowdefy, callbackUrl }) }, authUrl.urlQuery);
|
||||
}
|
||||
function logout({ callbackUrl }) {
|
||||
signOut({ callbackUrl: getCallbackUrl({ lowdefy, callbackUrl }) });
|
||||
}
|
||||
return {
|
||||
login,
|
||||
logout,
|
||||
};
|
||||
}
|
||||
|
||||
export default getAuthMethods;
|
92
packages/server/lib/utils/auth/getNextAuthConfig.js
Normal file
92
packages/server/lib/utils/auth/getNextAuthConfig.js
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import { getSecretsFromEnv } from '@lowdefy/node-utils';
|
||||
import { _secret } from '@lowdefy/operators-js/operators/server';
|
||||
|
||||
import authJson from '../../../build/auth.json';
|
||||
import getProviders from './getProviders.js';
|
||||
|
||||
const nextAuthConfig = {};
|
||||
let initialized = false;
|
||||
|
||||
const callbacks = {
|
||||
jwt: async ({ token, user, account, profile, isNewUser }) => {
|
||||
console.log('jwt callback');
|
||||
console.log('token', token);
|
||||
console.log('user', user);
|
||||
console.log('account', account);
|
||||
console.log('profile', profile);
|
||||
console.log('isNewUser', isNewUser);
|
||||
|
||||
return token;
|
||||
},
|
||||
session: async ({ session, user, token }) => {
|
||||
console.log('session callback');
|
||||
console.log('session', session);
|
||||
console.log('user', user);
|
||||
console.log('token', token);
|
||||
session.sub = token.sub;
|
||||
return session;
|
||||
},
|
||||
async redirect({ url, baseUrl }) {
|
||||
console.log('redirect callback', url, baseUrl);
|
||||
// Allows relative callback URLs
|
||||
if (url.startsWith('/')) return `${baseUrl}${url}`;
|
||||
// Allows callback URLs on the same origin
|
||||
else if (new URL(url).origin === baseUrl) return url;
|
||||
return baseUrl;
|
||||
},
|
||||
};
|
||||
|
||||
function getNextAuthConfig() {
|
||||
if (initialized) return nextAuthConfig;
|
||||
|
||||
const operatorsParser = new NodeParser({
|
||||
// TODO: do we want to support other operators here?
|
||||
operators: { _secret },
|
||||
payload: {},
|
||||
secrets: getSecretsFromEnv(),
|
||||
user: {},
|
||||
});
|
||||
|
||||
const { output: authConfig, errors: operatorErrors } = operatorsParser.parse({
|
||||
input: authJson,
|
||||
location: 'auth',
|
||||
});
|
||||
|
||||
if (operatorErrors.length > 0) {
|
||||
throw new Error(operatorErrors[0]);
|
||||
}
|
||||
|
||||
nextAuthConfig.providers = getProviders(authConfig);
|
||||
|
||||
// We can either configure this using auth config,
|
||||
// then the user configures this using the _secret operator
|
||||
// -> authConfig.secret = evaluatedAuthConfig.secret;
|
||||
// or we can create a fixed env var/secret name that we read.
|
||||
// -> authConfig.secret = secrets.LOWDEFY_AUTH_SECRET;
|
||||
nextAuthConfig.secret = 'TODO: Configure secret';
|
||||
|
||||
nextAuthConfig.callbacks = callbacks;
|
||||
nextAuthConfig.theme = authConfig.theme;
|
||||
initialized = true;
|
||||
console.log(JSON.stringify(nextAuthConfig, null, 2));
|
||||
return nextAuthConfig;
|
||||
}
|
||||
|
||||
export default getNextAuthConfig;
|
33
packages/server/lib/utils/auth/getProviders.js
Normal file
33
packages/server/lib/utils/auth/getProviders.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2020-2022 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import providers from '../../../build/plugins/auth/providers.js';
|
||||
|
||||
// TODO: docs:
|
||||
// Callback url to configure with provider will be: {{ protocol }}{{ host }}/api/auth/callback/{{ providerId }}
|
||||
// This depends on providerId, which might cause some issues if users copy an example and change the id.
|
||||
// We need to allow users to configure ids, since they might have more than one of the same type.
|
||||
|
||||
function getProviders(authConfig) {
|
||||
return authConfig.providers.map((provider) =>
|
||||
providers[provider.type]({
|
||||
...provider.properties,
|
||||
id: provider.id,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export default getProviders;
|
Loading…
x
Reference in New Issue
Block a user