Hello everyone.
This time, using the python library Flask, it corresponds to LINE login v2.1, I would like to make a test app.
https://developers.line.biz/ja/docs/line-login/integrate-line-login/
Install the required libraries. This time, we will use the following libraries.
Flask
requests
Flask-Session==0.3.0
uwsgi
gunicorn
argparse
https://github.com/myucy/line-login-v2.1-tester/blob/master/requirements.txt
Use the Python library https://pythonhosted.org/Flask-Session/. Since this is a test app, I created 32 random characters with simple logic and This is the session.
import random
import string
#Creating a unique key for a session
def randomstate(n):
randlst = [random.choice(string.ascii_letters + string.digits)
for i in range(n)]
return ''.join(randlst)
#Main page. state management with session library
@app.route('/', methods=['GET'])
def Mainpage():
# randomstate(n)Control state length with
session["state"] = randomstate(32)
return render_template('login.html',
state=session["state"]
)
Create a LINE login authorization request based on the POSTed content. https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request Even if there are multiple scopes, the scope value is looped out so that it can be handled.
from argparse import ArgumentParser
import json
import urllib.request
import requests
from flask import Flask, request, abort, render_template, jsonify, redirect, session
#Generate LINE login authorization request
@app.route('/login', methods=['POST'])
def authorizeReq():
scopes = ""
i = 0
for key in request.form.getlist("ScopeValue"):
if (i < 1):
i = i + 1
scopes = key
else:
scopes = scopes+" "+key
queries = {}
queries['response_type'] = 'code'
queries['client_id'] = request.form['ChannelIdValue']
queries['redirect_uri'] = request.form['redirect_uriValue']
queries['scope'] = scopes
queries['state'] = request.form['stateValue']
queries['prompt'] = request.form['promptValue']
queries['bot_prompt'] = request.form['bot_promptValue']
queries['nonce'] = request.form['nonceValue']
queries['max_age'] = request.form['max_ageValue']
queries['ui_locales'] = request.form['ui_localesValue']
authorize_url = 'https://access.line.me/oauth2/v2.1/authorize?' + \
urllib.parse.urlencode(queries)
return redirect(authorize_url)
It simply validates the state and handles errors (when the authorization request is canceled).
from argparse import ArgumentParser
import json
import urllib.request
import requests
from flask import Flask, request, abort, render_template, jsonify, redirect, session
@app.route('/callback', methods=['GET'])
def Callbackpage():
state = request.args.get('state')
error = request.args.get('error')
code = request.args.get('code')
#If you want to try it locally, uri= request.base_url
#When trying with an external server, specify the address starting with HTTTPS in uri
uri = "Enter the callback URL"
error_description = request.args.get('error_description')
#Verify state before error handling
expected_state = session.get('state')
if state != expected_state:
return "[Error] state does not match", 400
#Control of errors such as when an authorization request is canceled
if error:
return "[Error] Not Logined: " + error + "\n" + error_description, 400
return render_template('callback.html',
code=code,
state=state,
uri=uri
)
The test app also implements access token and ID token decoding. https://myucy-login.herokuapp.com/
By using the Flask-Session library, CSRF countermeasures can be taken very easily. Please implement it. Speaking of which, even if you log in to LINE, which is an official account with an authentication badge, you should have an account with a fixed state. You can see it here and there, but is that okay?
Source code https://github.com/myucy/line-login-v2.1-tester
Recommended Posts