Integrating LINE Login with your web app
This guide provides a detailed walkthrough for integrating LINE Login with your web application
Ensure you've thoroughly reviewed the official LINE Login integration documentation before proceeding.
Prerequisites
Familiarity with the LINE Login integration documentation.
Access to your LINE Developers Console.
Basic knowledge of web development.
Before you start
Ensure that your web app has been correctly integrated with the Antsomi Website SDK. If it hasn't, please refer to the documentation before proceeding further.
Preparation
Now that you're equipped with the prerequisite knowledge, let's prepare your web application for LINE Login integration.
<script>
async function generateCodeChallenge(codeVerifier) {
var digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
return btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}
function generateRandomString(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
</script>
Initialization
Initiate the integration process by setting up the necessary parameters and code for a smooth LINE Login experience in your web app.
<script>
document.addEventListener("DOMContentLoaded", function (event) {
var codeVerifier = generateRandomString(64);
const challengeMethod = crypto.subtle ? "S256" : "plain";
Promise.resolve()
.then(() => {
if (challengeMethod === 'S256') {
return generateCodeChallenge(codeVerifier);
}
else {
return codeVerifier;
}
})
.then(function (codeChallenge) {
window.sessionStorage.setItem("code_verifier", codeVerifier);
var redirectUri = window.location.href.split('?')[0];
var args = new URLSearchParams({
response_type: "code",
client_id: "<YOUR_CLIENT_ID>",
code_challenge_method: challengeMethod,
code_challenge: codeChallenge,
redirect_uri: redirectUri,
state: "12345",
scope: "profile openid"
});
window.location = "https://access.line.me/oauth2/v2.1/authorize/?" + args;
});
});
</script>
Replace "<YOUR_CLIENT_ID>"
with your actual LINE Login channel's client ID.
Token Exchange
Once initialized, proceed with the token exchange phase, where authentication codes are exchanged for access tokens, paving the way for seamless user interactions.
<script>
const authorizeEndpoint = "https://access.line.me/oauth2/v2.1/authorize";
const tokenEndpoint = "https://api.line.me/oauth2/v2.1/token";
const userEnpoint = "https://api.line.me/v2/profile";
const clientId = "<YOUR_CLIENT_ID>";
if (window.location.search) {
var args = new URLSearchParams(window.location.search);
var code = args.get("code");
if (code) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var response = xhr.response;
var message;
if (xhr.status == 200) {
// Token exchange successful
message = "Access Token: " + JSON.stringify(response);
}
else {
// Token exchange error
message = "Error: " + response.error_description + " (" + response.error + ")";
}
// Get user information
var xhrUser = new XMLHttpRequest();
xhrUser.responseType = 'json';
xhrUser.open("POST", userEnpoint, true);
xhrUser.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhrUser.setRequestHeader('Authorization', 'Bearer ' + response.access_token);
xhrUser.send(new URLSearchParams({
client_id: clientId,
id_token: response.id_token
}));
xhrUser.onload = function () {
var response = xhrUser.response;
// Store user information
window.atLineUID = response.userId;
window.atDisplayName = response.displayName;
// Track user login event
web_event.track("line_oa", "login", {
items: [],
dims: {},
extra: {
name: response.displayName,
username: response.displayName,
line_uid: response.userId
}
});
}
document.getElementById("result").innerHTML = message;
};
xhr.responseType = 'json';
xhr.open("POST", tokenEndpoint, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(new URLSearchParams({
client_id: clientId,
client_secret: "<YOUR_CLIENT_SECRET>",
code_verifier: window.sessionStorage.getItem("code_verifier"),
grant_type: "authorization_code",
redirect_uri: location.href.replace(location.search, ''),
code: code
}));
}
}
</script>
Replace "<YOUR_CLIENT_SECRET>"
with your actual LINE Login channel's client ID.
Example
By diligently following the Preparation, Initialization, and Token Exchange steps, you will seamlessly integrate LINE Login into your web application. Below is an example script demonstrating the entire process:
<script>
const authorizeEndpoint = "https://access.line.me/oauth2/v2.1/authorize";
const tokenEndpoint = "https://api.line.me/oauth2/v2.1/token";
const userEnpoint = "https://api.line.me/v2/profile";
const clientId = "<CLIENT_ID>";
const clientSecrect = "<CLIENT_SECRECT>";
if (window.location.search) {
var args = new URLSearchParams(window.location.search);
var code = args.get("code");
if (code) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var response = xhr.response;
var message;
if (xhr.status == 200) {
message = "Access Token: " + JSON.stringify(response);
}
else {
message = "Error: " + response.error_description + " (" + response.error + ")";
}
// get info user
var xhrUser = new XMLHttpRequest();
xhrUser.responseType = 'json';
xhrUser.open("POST", userEnpoint, true);
xhrUser.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhrUser.setRequestHeader('Authorization', 'Bearer ' + response.access_token);
xhrUser.send(new URLSearchParams({
client_id: clientId,
id_token: response.id_token
}));
xhrUser.onload = function () {
var response = xhrUser.response;
window.atLineUID = response.userId;
window.atDisplayName = response.displayName;
web_event.track("line_oa", "login", {
items: [],
dims: {},
extra: {
name: response.displayName,
username: response.displayName,
line_uid: response.userId
}
});
}
document.getElementById("result").innerHTML = message;
};
xhr.responseType = 'json';
xhr.open("POST", tokenEndpoint, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
code_verifier: window.sessionStorage.getItem("code_verifier"),
grant_type: "authorization_code",
redirect_uri: location.href.replace(location.search, ''),
code: code
}));
}
}
else {
document.addEventListener("DOMContentLoaded", function (event) {
var codeVerifier = generateRandomString(64);
const challengeMethod = crypto.subtle ? "S256" : "plain";
Promise.resolve()
.then(() => {
if (challengeMethod === 'S256') {
return generateCodeChallenge(codeVerifier);
}
else {
return codeVerifier;
}
})
.then(function (codeChallenge) {
window.sessionStorage.setItem("code_verifier", codeVerifier);
var redirectUri = window.location.href.split('?')[0];
var args = new URLSearchParams({
response_type: "code",
client_id: clientId,
code_challenge_method: challengeMethod,
code_challenge: codeChallenge,
redirect_uri: redirectUri,
state: "12345",
scope: "profile openid"
});
window.location = authorizeEndpoint + "/?" + args;
});
});
}
async function generateCodeChallenge(codeVerifier) {
var digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
return btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
}
function generateRandomString(length) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
</script>
Last updated