I’m developing a Web Application using Flask as framework and I would like to achieve the authentication of users to my IdP (Azure AD) from two different flows: 1- Normal users navigating through the browser. 2- API users with no access to browser
An example of what I mean is:
@app.route('/')
@oidc.require_login
def hello_world():
return ("Hello logged in User")
@app.route('/apiLogin', methods=['POST'])
def login():
username = request.json.get('username')
password = request.json.get('password')
token = login(username, password)
if token:
return redirect(url_for("hello_world"))
else:
return jsonify({'error': 'Authentication failed'}), 401
The route “/” directly redirects browser users to Azure AD to authenticate thanks to the @oidc.require_login wrapper. Instead, for API users I intend to create an endpoint for them to authenticate using user/password | token | cert -or whatever method- and once the login is successful they will have access to API endpoints similar to browser endpoints.
I tried to do that directly with Flask MSAL and Identity libraries but had no luck for API users, I achieved browser users to connect to the application and login succesfully. Then I tried to add Keycloak to the equation as an IdP broker, but I arrived to the exact same point, browser authentication works as a charm but I can’t find a way to authenticate API users without any browser interaction.
How can I achieve API authentication with Azure AD without browser, am I missing any authentication flow/endpoint in Keycloak? I also tried the following with Keycloak but requests are not going through the IdP, I get the following error: “Unable to find matching target resource method”.
KEYCLOAK_URL = 'http://localhost:8081/auth/realms/flaskAppTest/protocol/openid-connect/token'
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username')
password = request.json.get('password')
# Use ROPC auth flow
response = requests.post(
KEYCLOAK_URL,
data={
'grant_type': 'password',
'client_id': 'client_id',
'client_secret': 'secret',
'username': username,
'password': password,
}
)