[{"data":1,"prerenderedAt":966},["ShallowReactive",2],{"h2107759030":3,"h3043944747":589,"h4071363574":959},{"id":4,"title":5,"body":6,"description":28,"extension":581,"meta":582,"navigation":106,"path":585,"seo":586,"stem":587,"__hash__":588},"docs\u002Fen\u002Ftips\u002F2026\u002F08\u002F13\u002Fsend-token-to-server.md","Send tokens, not profile data, to your server",{"type":7,"value":8,"toc":564},"minimark",[9],[10,11,12,20,25,29,32,37,49,56,199,205,210,216,222,232,236,244,247,251,254,293,405,412,433,437,440,454,461,472,476,479,534,538,541,554,558],"Tips",{},[13,14,17],"h1",{"id":15,"class":16},"","!mb-4",[18,19],"page-title",{},[21,22],"display-date",{"date":23,"class":24},"2026\u002F08\u002F13","!mb-20",[26,27,28],"p",{},"When integrating LINE Login or developing a LINE MINI App, you may notice that you can get profile information such as an end user's user ID and display name. It might seem that you can send the profile information to your service's server and use it as is for login or account linking.",[26,30,31],{},"However, for security reasons, a client shouldn't send profile information such as a user ID to a server as the basis for user authentication. This article explains the basic approach to securely identifying users on your server.",[33,34,36],"h2",{"id":35},"client-profile-can-be-tampered-with","Profile information sent by a client can be tampered with",[26,38,39,40,48],{},"For example, you can use ",[41,42,44],"a",{"href":43},"\u002Freference\u002Fliff\u002F#get-profile",[45,46,47],"code",{},"liff.getProfile()"," to get the user's ID, display name, and other information in a LIFF app. You can use this information to show the user's profile in the LIFF app's UI.",[26,50,51,52,55],{},"However, the following implementation, which sends the retrieved information to the server and treats ",[45,53,54],{},"userId"," as the logged-in user, isn't secure:",[57,58,62],"pre",{"className":59,"code":60,"language":61,"meta":15,"style":15},"language-javascript shiki shiki-themes github-dark-default","\u002F\u002F Incorrect example: Send a user ID to the server\nconst profile = await liff.getProfile();\n\nawait fetch(\"\u002Fapi\u002Flogin\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application\u002Fjson\" },\n  body: JSON.stringify({\n    userId: profile.userId,\n    displayName: profile.displayName,\n  }),\n});\n","javascript",[45,63,64,73,101,108,127,139,157,175,181,187,193],{"__ignoreMap":15},[65,66,69],"span",{"class":67,"line":68},"line",1,[65,70,72],{"class":71},"sH3jZ","\u002F\u002F Incorrect example: Send a user ID to the server\n",[65,74,76,80,84,87,90,94,98],{"class":67,"line":75},2,[65,77,79],{"class":78},"suJrU","const",[65,81,83],{"class":82},"sFSAA"," profile",[65,85,86],{"class":78}," =",[65,88,89],{"class":78}," await",[65,91,93],{"class":92},"sZEs4"," liff.",[65,95,97],{"class":96},"sc3cj","getProfile",[65,99,100],{"class":92},"();\n",[65,102,104],{"class":67,"line":103},3,[65,105,107],{"emptyLinePlaceholder":106},true,"\n",[65,109,111,114,117,120,124],{"class":67,"line":110},4,[65,112,113],{"class":78},"await",[65,115,116],{"class":96}," fetch",[65,118,119],{"class":92},"(",[65,121,123],{"class":122},"s9uIt","\"\u002Fapi\u002Flogin\"",[65,125,126],{"class":92},", {\n",[65,128,130,133,136],{"class":67,"line":129},5,[65,131,132],{"class":92},"  method: ",[65,134,135],{"class":122},"\"POST\"",[65,137,138],{"class":92},",\n",[65,140,142,145,148,151,154],{"class":67,"line":141},6,[65,143,144],{"class":92},"  headers: { ",[65,146,147],{"class":122},"\"Content-Type\"",[65,149,150],{"class":92},": ",[65,152,153],{"class":122},"\"application\u002Fjson\"",[65,155,156],{"class":92}," },\n",[65,158,160,163,166,169,172],{"class":67,"line":159},7,[65,161,162],{"class":92},"  body: ",[65,164,165],{"class":82},"JSON",[65,167,168],{"class":92},".",[65,170,171],{"class":96},"stringify",[65,173,174],{"class":92},"({\n",[65,176,178],{"class":67,"line":177},8,[65,179,180],{"class":92},"    userId: profile.userId,\n",[65,182,184],{"class":67,"line":183},9,[65,185,186],{"class":92},"    displayName: profile.displayName,\n",[65,188,190],{"class":67,"line":189},10,[65,191,192],{"class":92},"  }),\n",[65,194,196],{"class":67,"line":195},11,[65,197,198],{"class":92},"});\n",[26,200,201,202,204],{},"Users can modify code running in a browser or app and the requests sent by that code. If an attacker replaces the ",[45,203,54],{}," in the request with a different value, the server has no way to determine whether that value came from the LINE Platform. Using only this value for login or account linking could allow an attacker to impersonate another user.",[26,206,207,208,168],{},"The following sequence diagram shows how an attacker who knows another user's user ID can impersonate that user by replacing the ",[45,209,54],{},[211,212],"interactive-svg",{"src":213,"alt":214,":border":215},"\u002Fmedia\u002Ftips\u002F2026\u002Fsend-token-to-server-impersonation.svg","Sequence diagram showing an attacker replacing the user ID sent by a LIFF app and a server issuing a session for another user without verification","true",[26,217,218,219,221],{},"Suppose an attacker somehow obtains another user's user ID and replaces the ",[45,220,54],{}," in a login request with that value. If the server issues a session without verifying the value, the attacker could log in as that user, view their account information or reservation history, or fraudulently use their points or coupons. A user ID isn't a password and can't be used by itself to verify a user's identity.",[26,223,224,225,231],{},"For the same reason, don't send profile information obtained with ",[41,226,228],{"href":227},"\u002Freference\u002Fliff\u002F#get-decoded-id-token",[45,229,230],{},"liff.getDecodedIDToken()"," to your server for user authentication.",[33,233,235],{"id":234},"send-and-verify-token","Send the raw token and verify it on the server",[26,237,238,239,243],{},"To identify a user on your server, send a ",[240,241,242],"strong",{},"raw ID token or access token"," from the client instead of a user ID. The server then calls a LINE Platform API to verify the token and gets the user ID from the verification result.",[26,245,246],{},"The following sequence diagram shows the overall flow when using an ID token.",[211,248],{"src":249,"alt":250,":border":215},"\u002Fmedia\u002Fliff\u002Fsend-user-profile-via-id-token.svg","Sequence diagram showing a LIFF app sending an ID token to the service's server and the server verifying it with the LINE Platform",[26,252,253],{},"The important point is that the LIFF app sends the raw ID token, not profile information, to your service's server, and the server uses the verification result received directly from the LINE Platform. The specific steps are as follows:",[255,256,257,275,278,286],"ol",{},[258,259,260,261,267,268,274],"li",{},"After ",[41,262,264],{"href":263},"\u002Freference\u002Fliff\u002F#initialize-liff-app",[45,265,266],{},"liff.init()"," completes, call ",[41,269,271],{"href":270},"\u002Freference\u002Fliff\u002F#get-id-token",[45,272,273],{},"liff.getIDToken()"," in the LIFF app to get the raw ID token",[258,276,277],{},"Send the ID token to your service's server over HTTPS",[258,279,280,281,285],{},"From the server, send the ID token and expected channel ID to the ",[41,282,284],{"href":283},"\u002Freference\u002Fline-login\u002F#verify-id-token","Verify ID token"," endpoint",[258,287,288,289,292],{},"Treat the ",[45,290,291],{},"sub"," in a successful verification response as the LINE user ID",[57,294,296],{"className":59,"code":295,"language":61,"meta":15,"style":15},"const idToken = liff.getIDToken();\nif (!idToken) {\n  throw new Error(\"ID token is unavailable\");\n}\n\nawait fetch(\"\u002Fapi\u002Flogin\", {\n  method: \"POST\",\n  headers: { \"Content-Type\": \"application\u002Fjson\" },\n  body: JSON.stringify({ idToken }),\n});\n",[45,297,298,314,328,347,352,356,368,376,388,401],{"__ignoreMap":15},[65,299,300,302,305,307,309,312],{"class":67,"line":68},[65,301,79],{"class":78},[65,303,304],{"class":82}," idToken",[65,306,86],{"class":78},[65,308,93],{"class":92},[65,310,311],{"class":96},"getIDToken",[65,313,100],{"class":92},[65,315,316,319,322,325],{"class":67,"line":75},[65,317,318],{"class":78},"if",[65,320,321],{"class":92}," (",[65,323,324],{"class":78},"!",[65,326,327],{"class":92},"idToken) {\n",[65,329,330,333,336,339,341,344],{"class":67,"line":103},[65,331,332],{"class":78},"  throw",[65,334,335],{"class":78}," new",[65,337,338],{"class":96}," Error",[65,340,119],{"class":92},[65,342,343],{"class":122},"\"ID token is unavailable\"",[65,345,346],{"class":92},");\n",[65,348,349],{"class":67,"line":110},[65,350,351],{"class":92},"}\n",[65,353,354],{"class":67,"line":129},[65,355,107],{"emptyLinePlaceholder":106},[65,357,358,360,362,364,366],{"class":67,"line":141},[65,359,113],{"class":78},[65,361,116],{"class":96},[65,363,119],{"class":92},[65,365,123],{"class":122},[65,367,126],{"class":92},[65,369,370,372,374],{"class":67,"line":159},[65,371,132],{"class":92},[65,373,135],{"class":122},[65,375,138],{"class":92},[65,377,378,380,382,384,386],{"class":67,"line":177},[65,379,144],{"class":92},[65,381,147],{"class":122},[65,383,150],{"class":92},[65,385,153],{"class":122},[65,387,156],{"class":92},[65,389,390,392,394,396,398],{"class":67,"line":183},[65,391,162],{"class":92},[65,393,165],{"class":82},[65,395,168],{"class":92},[65,397,171],{"class":96},[65,399,400],{"class":92},"({ idToken }),\n",[65,402,403],{"class":67,"line":189},[65,404,198],{"class":92},[26,406,407,408,411],{},"When integrating LINE Login into a web app, the backend normally sends the authorization code returned to the callback URL to the LINE Platform's token endpoint. The backend then gets an access token and, if the ",[45,409,410],{},"openid"," scope was specified, an ID token. In this case, identify the user from the token obtained and verified by the backend, instead of using a user ID sent from the browser.",[26,413,414,415,419,420,423,424,427,428,432],{},"You can also use an access token. On your server, call the ",[41,416,418],{"href":417},"\u002Freference\u002Fline-login\u002F#verify-access-token","Verify access token validity"," endpoint and confirm that the ",[45,421,422],{},"client_id"," in the verification result matches the expected channel ID and that ",[45,425,426],{},"expires_in"," is a positive value. Then get the user ID from the ",[41,429,431],{"href":430},"\u002Freference\u002Fline-login\u002F#get-user-profile","Get user profile"," endpoint.",[33,434,436],{"id":435},"exchange-for-application-session","Exchange the verified token for your service's session",[26,438,439],{},"After getting the verified user ID, issue a session for your service. Use that session to manage the user's login state in subsequent requests.",[255,441,442,445,448,451],{},[258,443,444],{},"For a LIFF app, send the ID token or access token to your service's server. For LINE Login integrated into a web app, the backend exchanges the authorization code for tokens",[258,446,447],{},"Call a LINE Platform API from your service's server to verify the token",[258,449,450],{},"Get the user ID from the verification result",[258,452,453],{},"Issue a session for your service based on the obtained user ID",[26,455,456,457,460],{},"Avoid using a token from the LINE Platform as a long-lived session for your service. In particular, an access token obtained by a LIFF app may be revoked when the user closes the LIFF app. Therefore, implementations that save the token to ",[45,458,459],{},"localStorage"," or a similar location and reuse it the next time the app is opened can cause authentication to fail unexpectedly.",[26,462,463,464,467,468,471],{},"ID tokens and access tokens are credentials. Send them over HTTPS, and don't record them in logs or analytics tools. If you use cookies to manage sessions for your service, protect the session itself appropriately, such as by setting the ",[45,465,466],{},"Secure"," and ",[45,469,470],{},"HttpOnly"," attributes.",[33,473,475],{"id":474},"choose-the-right-data","Choose the right data for each purpose",[26,477,478],{},"The same user information must be handled differently on the client and the server.",[480,481,482,495],"table",{},[483,484,485],"thead",{},[486,487,488,492],"tr",{},[489,490,491],"th",{},"Purpose",[489,493,494],{},"Information to use",[496,497,498,512,526],"tbody",{},[486,499,500,504],{},[501,502,503],"td",{},"Show a display name or profile image in the LIFF app's UI",[501,505,506,507,509,510],{},"Information obtained with ",[45,508,47],{}," or ",[45,511,230],{},[486,513,514,517],{},[501,515,516],{},"Identify a user on the server",[501,518,519,520,509,522,525],{},"The result of verifying a raw token obtained with ",[45,521,273],{},[45,523,524],{},"liff.getAccessToken()"," on the server",[486,527,528,531],{},[501,529,530],{},"Maintain login state after verification",[501,532,533],{},"A session issued by your service",[33,535,537],{"id":536},"wrap-up","Wrap-up",[26,539,540],{},"Profile information obtained on a client can be displayed to the end user, but it can be tampered with. Therefore, using it as is as the basis for user authentication on the server is unsafe. To identify a user on your server, receive a raw ID token or access token and use the result of verifying it with the LINE Platform.",[26,542,543,544,548,549,553],{},"For more information, see ",[41,545,547],{"href":546},"\u002Fdocs\u002Fliff\u002Fusing-user-profile\u002F","Using user data in LIFF apps and servers"," in the LIFF documentation and ",[41,550,552],{"href":551},"\u002Fdocs\u002Fline-login\u002Fsecurity-checklist\u002F","LINE Login security checklist"," in the LINE Login documentation.",[555,556,557],"style",{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",[559,560],"tags",{"tags":561,"lang":562,"section":563},"line-login, liff, line-mini-app","en","tips",{"title":15,"searchDepth":110,"depth":129,"links":565},[566,569,572,575,578],{"id":567,"depth":75,"text":568},"profile-information-sent-by-a-client-can-be-tampered-with-client-profile-can-be-tampered-with","Profile information sent by a client can be tampered with {#client-profile-can-be-tampered-with}",{"id":570,"depth":75,"text":571},"send-the-raw-token-and-verify-it-on-the-server-send-and-verify-token","Send the raw token and verify it on the server {#send-and-verify-token}",{"id":573,"depth":75,"text":574},"exchange-the-verified-token-for-your-services-session-exchange-for-application-session","Exchange the verified token for your service's session {#exchange-for-application-session}",{"id":576,"depth":75,"text":577},"choose-the-right-data-for-each-purpose-choose-the-right-data","Choose the right data for each purpose {#choose-the-right-data}",{"id":579,"depth":75,"text":580},"wrap-up-wrap-up","Wrap-up {#wrap-up}","md",{"date":583,"tags":561,"locale":562,"sidebar":584},"2026-08-13 00:00 UTC",false,"\u002Fen\u002Ftips\u002F2026\u002F08\u002F13\u002Fsend-token-to-server",{"title":5,"description":28},"en\u002Ftips\u002F2026\u002F08\u002F13\u002Fsend-token-to-server","8UrKIwPq7_h-P4cPrJsouy_5y2UOSquitSZtuWkxgxI",{"id":4,"title":5,"body":590,"description":28,"extension":581,"meta":957,"navigation":106,"path":585,"seo":958,"stem":587,"__hash__":588},{"type":7,"value":591,"toc":950},[592],[10,593,594,598,600,602,604,606,612,616,704,708,712,714,718,724,726,730,732,734,736,758,856,860,870,872,874,884,888,894,896,898,936,938,940,946,948],{},[13,595,596],{"id":15,"class":16},[18,597],{},[21,599],{"date":23,"class":24},[26,601,28],{},[26,603,31],{},[33,605,36],{"id":35},[26,607,39,608,48],{},[41,609,610],{"href":43},[45,611,47],{},[26,613,51,614,55],{},[45,615,54],{},[57,617,618],{"className":59,"code":60,"language":61,"meta":15,"style":15},[45,619,620,624,640,644,656,664,676,688,692,696,700],{"__ignoreMap":15},[65,621,622],{"class":67,"line":68},[65,623,72],{"class":71},[65,625,626,628,630,632,634,636,638],{"class":67,"line":75},[65,627,79],{"class":78},[65,629,83],{"class":82},[65,631,86],{"class":78},[65,633,89],{"class":78},[65,635,93],{"class":92},[65,637,97],{"class":96},[65,639,100],{"class":92},[65,641,642],{"class":67,"line":103},[65,643,107],{"emptyLinePlaceholder":106},[65,645,646,648,650,652,654],{"class":67,"line":110},[65,647,113],{"class":78},[65,649,116],{"class":96},[65,651,119],{"class":92},[65,653,123],{"class":122},[65,655,126],{"class":92},[65,657,658,660,662],{"class":67,"line":129},[65,659,132],{"class":92},[65,661,135],{"class":122},[65,663,138],{"class":92},[65,665,666,668,670,672,674],{"class":67,"line":141},[65,667,144],{"class":92},[65,669,147],{"class":122},[65,671,150],{"class":92},[65,673,153],{"class":122},[65,675,156],{"class":92},[65,677,678,680,682,684,686],{"class":67,"line":159},[65,679,162],{"class":92},[65,681,165],{"class":82},[65,683,168],{"class":92},[65,685,171],{"class":96},[65,687,174],{"class":92},[65,689,690],{"class":67,"line":177},[65,691,180],{"class":92},[65,693,694],{"class":67,"line":183},[65,695,186],{"class":92},[65,697,698],{"class":67,"line":189},[65,699,192],{"class":92},[65,701,702],{"class":67,"line":195},[65,703,198],{"class":92},[26,705,201,706,204],{},[45,707,54],{},[26,709,207,710,168],{},[45,711,54],{},[211,713],{"src":213,"alt":214,":border":215},[26,715,218,716,221],{},[45,717,54],{},[26,719,224,720,231],{},[41,721,722],{"href":227},[45,723,230],{},[33,725,235],{"id":234},[26,727,238,728,243],{},[240,729,242],{},[26,731,246],{},[211,733],{"src":249,"alt":250,":border":215},[26,735,253],{},[255,737,738,748,750,754],{},[258,739,260,740,267,744,274],{},[41,741,742],{"href":263},[45,743,266],{},[41,745,746],{"href":270},[45,747,273],{},[258,749,277],{},[258,751,280,752,285],{},[41,753,284],{"href":283},[258,755,288,756,292],{},[45,757,291],{},[57,759,760],{"className":59,"code":295,"language":61,"meta":15,"style":15},[45,761,762,776,786,800,804,808,820,828,840,852],{"__ignoreMap":15},[65,763,764,766,768,770,772,774],{"class":67,"line":68},[65,765,79],{"class":78},[65,767,304],{"class":82},[65,769,86],{"class":78},[65,771,93],{"class":92},[65,773,311],{"class":96},[65,775,100],{"class":92},[65,777,778,780,782,784],{"class":67,"line":75},[65,779,318],{"class":78},[65,781,321],{"class":92},[65,783,324],{"class":78},[65,785,327],{"class":92},[65,787,788,790,792,794,796,798],{"class":67,"line":103},[65,789,332],{"class":78},[65,791,335],{"class":78},[65,793,338],{"class":96},[65,795,119],{"class":92},[65,797,343],{"class":122},[65,799,346],{"class":92},[65,801,802],{"class":67,"line":110},[65,803,351],{"class":92},[65,805,806],{"class":67,"line":129},[65,807,107],{"emptyLinePlaceholder":106},[65,809,810,812,814,816,818],{"class":67,"line":141},[65,811,113],{"class":78},[65,813,116],{"class":96},[65,815,119],{"class":92},[65,817,123],{"class":122},[65,819,126],{"class":92},[65,821,822,824,826],{"class":67,"line":159},[65,823,132],{"class":92},[65,825,135],{"class":122},[65,827,138],{"class":92},[65,829,830,832,834,836,838],{"class":67,"line":177},[65,831,144],{"class":92},[65,833,147],{"class":122},[65,835,150],{"class":92},[65,837,153],{"class":122},[65,839,156],{"class":92},[65,841,842,844,846,848,850],{"class":67,"line":183},[65,843,162],{"class":92},[65,845,165],{"class":82},[65,847,168],{"class":92},[65,849,171],{"class":96},[65,851,400],{"class":92},[65,853,854],{"class":67,"line":189},[65,855,198],{"class":92},[26,857,407,858,411],{},[45,859,410],{},[26,861,414,862,419,864,423,866,427,868,432],{},[41,863,418],{"href":417},[45,865,422],{},[45,867,426],{},[41,869,431],{"href":430},[33,871,436],{"id":435},[26,873,439],{},[255,875,876,878,880,882],{},[258,877,444],{},[258,879,447],{},[258,881,450],{},[258,883,453],{},[26,885,456,886,460],{},[45,887,459],{},[26,889,463,890,467,892,471],{},[45,891,466],{},[45,893,470],{},[33,895,475],{"id":474},[26,897,478],{},[480,899,900,908],{},[483,901,902],{},[486,903,904,906],{},[489,905,491],{},[489,907,494],{},[496,909,910,920,930],{},[486,911,912,914],{},[501,913,503],{},[501,915,506,916,509,918],{},[45,917,47],{},[45,919,230],{},[486,921,922,924],{},[501,923,516],{},[501,925,519,926,509,928,525],{},[45,927,273],{},[45,929,524],{},[486,931,932,934],{},[501,933,530],{},[501,935,533],{},[33,937,537],{"id":536},[26,939,540],{},[26,941,543,942,548,944,553],{},[41,943,547],{"href":546},[41,945,552],{"href":551},[555,947,557],{},[559,949],{"tags":561,"lang":562,"section":563},{"title":15,"searchDepth":110,"depth":129,"links":951},[952,953,954,955,956],{"id":567,"depth":75,"text":568},{"id":570,"depth":75,"text":571},{"id":573,"depth":75,"text":574},{"id":576,"depth":75,"text":577},{"id":579,"depth":75,"text":580},{"date":583,"tags":561,"locale":562,"sidebar":584},{"title":5,"description":28},{"toc":960,"fullToc":960},[961,962,963,964,965],{"id":35,"depth":75,"text":36},{"id":234,"depth":75,"text":235},{"id":435,"depth":75,"text":436},{"id":474,"depth":75,"text":475},{"id":536,"depth":75,"text":537},1786599678687]