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