Hello!
With the new(ish) auth provider system, I was waiting to see when OpenID Connect/OAuth support would get added. Ideally this would use the proper OAuth flow with redirects and such.
However, I don’t really see any discussions or interest on the boards/github/etc. Implementing it correctly would require a new auth provider type and require a significant amount of work.
Meanwhile! I have an (almost! see, below) working script that uses the command line auth plugin, and queries the OIDC provider. The script was tested against Keycloak, but other OpenID Connect providers should work as well.
#!/usr/bin/env python3
"""
Login to home assistant using OpenID Connect.
"""
import os
import sys
import json
import base64
from urllib.error import URLError, HTTPError
from urllib.parse import urlencode
from urllib.request import Request, urlopen
def eprint(message):
"""
Print error message to HA logs via stdout and exit the script with failure.
"""
print(message, file=sys.stderr)
sys.exit(1)
USERNAME = os.environ['username']
PASSWORD = os.environ['password']
CLIENT_ID = "XXXX"
CLIENT_SECRET = "XXXX"
REQUIRED_ROLE = "XXXX"
TOKEN_ENDPOINT = "https://keycloak.example.net/auth/realms/primary/protocol/openid-connect/token"
try:
DATA = {'grant_type': 'password',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'username': USERNAME,
'password': PASSWORD}
REQUEST = Request(TOKEN_ENDPOINT, urlencode(DATA).encode())
RESPONSE = json.loads(urlopen(REQUEST).read().decode())
TOKEN_RAW = RESPONSE['access_token'].split('.')[1]
TOKEN_PADDING = len(TOKEN_RAW) % 4
except (URLError, HTTPError):
eprint('Login failed: could not connect to oidc token endpoint: '
+ TOKEN_ENDPOINT)
ACCESS_RAW = base64.urlsafe_b64decode(
TOKEN_RAW + '=' * TOKEN_PADDING)
ACCESS_TOKEN = json.loads(ACCESS_RAW.decode('utf-8'))
ROLE_LIST = ACCESS_TOKEN['realm_access']['roles']
if REQUIRED_ROLE not in ROLE_LIST:
eprint('User is not authorized. required role "'
+ REQUIRED_ROLE + '" not found.')
print("name = " + ACCESS_TOKEN['name'])
EDIT: Rewrote using urlib to avoid dependencies. Not quite as clean but it works now.
Using OIDC in this way seems like a bit of an abuse/misuse, and I’m not super happy with how the command line auth passes username/password as part of command parameters, but this was at the very least a nice learning experience, and a stopgap measure until motivation for proper support can be found.