Skip to content

Instantly share code, notes, and snippets.

@hand-dot
Last active January 18, 2024 07:30
Show Gist options
  • Select an option

  • Save hand-dot/b37fa4a3aebe1ad54523d8416b3f6ed6 to your computer and use it in GitHub Desktop.

Select an option

Save hand-dot/b37fa4a3aebe1ad54523d8416b3f6ed6 to your computer and use it in GitHub Desktop.
Wix SSO with Line
import { response, serverError } from 'wix-http-functions';
import { authentication } from 'wix-members-backend';
import wixData from 'wix-data';
import { fetch } from 'wix-fetch';
import { CLIENT_ID, CLIENT_SECRET, BASE_URL, LINE_TOKEN_URL, LINE_VERIFY_URL } from './constants';
async function fetchToken(request) {
const tokenResponse = await fetch(LINE_TOKEN_URL, {
method: "POST",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'grant_type': 'authorization_code',
'code': request.query.code,
'redirect_uri': `${BASE_URL}/_functions/getAuth`,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
}).toString(),
});
if (!tokenResponse.ok) {
throw new Error(`Failed to get token from Line: ${tokenResponse.status} ${tokenResponse.statusText}`);
}
return await tokenResponse.json();
}
async function verifyToken(idToken) {
const verifyResponse = await fetch(LINE_VERIFY_URL, {
method: "POST",
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
'id_token': idToken,
'client_id': CLIENT_ID
}).toString(),
});
if (!verifyResponse.ok) {
throw new Error(`Failed to verify token from Line: ${verifyResponse.status} ${verifyResponse.statusText}`);
}
return await verifyResponse.json();
}
async function registerOrGetUser(userDetail) {
const { email, name, picture, sub: tmpPass } = userDetail;
const memberResults = await wixData.query('Members/FullData')
.contains('loginEmail', email)
.limit(1)
.find({ 'suppressAuth': true }).then(r => r.items);
console.log({ memberResults });
if (memberResults.length === 0) {
const registrationResult = await authentication.register(email, tmpPass, {
contactInfo: {
firstName: name.split(' ')[0] || '',
lastName: name.split(' ')[1] || '',
emails: [email],
picture: picture
}
});
if (registrationResult.status !== 'ACTIVE') {
throw new Error(`Failed to register user: User status is not active`);
}
}
}
export async function get_getAuth(request) {
try {
const tokenData = await fetchToken(request);
const userDetail = await verifyToken(tokenData.id_token);
await registerOrGetUser(userDetail);
const sessionToken = await authentication.generateSessionToken(userDetail.email);
return response({
status: 302,
headers: { 'Location': `${BASE_URL}?sessionToken=${sessionToken}` }
});
} catch (err) {
console.error(err);
return serverError({
body: { "error": err.message },
headers: { "Content-Type": "application/json" }
});
}
}
import wixLocationFrontend from 'wix-location-frontend';
import { authentication } from 'wix-members-frontend';
import { CLIENT_ID, REDIRECT_URL, LINE_AUTH_URL, SCOPE } from './constants';
$w.onReady(async function () {
const query = wixLocationFrontend.query;
if (query.sessionToken) {
const sessionToken = query.sessionToken;
authentication.applySessionToken(sessionToken)
wixLocationFrontend.queryParams.remove(["sessionToken"]);
}
$w('#loginLine').onClick(lineLogin);
});
function generateRandomState() {
return Math.random().toString(36).slice(3);
}
function createLoginLink(clientId, redirectUrl, state, scope) {
return `${LINE_AUTH_URL}?response_type=code&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUrl)}&state=${state}&scope=${encodeURIComponent(scope)}`;
}
function lineLogin() {
const state = generateRandomState();
const loginLink = createLoginLink(CLIENT_ID, REDIRECT_URL, state, SCOPE);
wixLocationFrontend.to(loginLink);
}