Compare commits
14 Commits
main
...
v0.6.3-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
951f85816d | ||
|
|
99603b4b25 | ||
|
|
6d32757829 | ||
|
|
833360a66d | ||
|
|
c821ac19f7 | ||
|
|
e601a63a3d | ||
|
|
17a96da715 | ||
|
|
11b29f2f3b | ||
|
|
b1519b865d | ||
|
|
7a31b10d0e | ||
|
|
a6955e64a0 | ||
|
|
c217e46909 | ||
|
|
f614092af2 | ||
|
|
4f29740fa0 |
3
.github/workflows/hacs.yaml
vendored
3
.github/workflows/hacs.yaml
vendored
@@ -13,10 +13,9 @@ jobs:
|
|||||||
validate:
|
validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: HACS validation
|
- name: HACS validation
|
||||||
uses: hacs/action@22.5.0
|
uses: hacs/action@22.5.0
|
||||||
with:
|
with:
|
||||||
category: "integration"
|
category: "integration"
|
||||||
ignore: brands
|
|
||||||
|
|
||||||
2
.github/workflows/hassfest.yaml
vendored
2
.github/workflows/hassfest.yaml
vendored
@@ -13,5 +13,5 @@ jobs:
|
|||||||
validate:
|
validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- uses: home-assistant/actions/hassfest@master
|
- uses: home-assistant/actions/hassfest@master
|
||||||
16
.github/workflows/lint.yaml
vendored
16
.github/workflows/lint.yaml
vendored
@@ -9,12 +9,16 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: Install the latest version of rye
|
- name: "Set up Python"
|
||||||
uses: eifinger/setup-rye@v4
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version-file: ".python-version"
|
||||||
|
- name: Install the latest version of uv
|
||||||
|
uses: astral-sh/setup-uv@v6
|
||||||
with:
|
with:
|
||||||
enable-cache: true
|
enable-cache: true
|
||||||
- name: Sync dependencies
|
- name: Sync dependencies
|
||||||
run: rye sync
|
run: scripts/sync
|
||||||
- name: Lint (pylint/rye lint)
|
- name: Lint (pylint/ruff lint)
|
||||||
run: rye run check
|
run: scripts/check
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.13.1
|
3.13.7
|
||||||
|
|||||||
@@ -13,9 +13,30 @@ If you are not a programmer, you can still contribute by:
|
|||||||
You may also submit Pull Requests (PRs) to add features yourself! You can find a list that we are currently working on below. Please note that workflows will be run on your pull request and a pull request will only be merged when all checks pass and a review has been conducted (together with a manual test).
|
You may also submit Pull Requests (PRs) to add features yourself! You can find a list that we are currently working on below. Please note that workflows will be run on your pull request and a pull request will only be merged when all checks pass and a review has been conducted (together with a manual test).
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
This project uses the Rye package manager for development. You can find installation instructions here: https://rye.astral.sh/guide/installation/. Start by installing the dependencies using rye sync and then point your editor towards the environment created in the .venv directory.
|
This project uses the uv package manager for development. You can find installation instructions here: https://docs.astral.sh/uv/getting-started/installation/. Start by installing the dependencies using `uv sync` and then point your editor towards the environment created in the .venv directory.
|
||||||
You can then run Home Assistant and put the `custom_components/auth_oidc` directory in your HA `config` folder.
|
You can then run Home Assistant and put the `custom_components/auth_oidc` directory in your HA `config` folder.
|
||||||
|
|
||||||
|
#### Other useful commands
|
||||||
|
Some useful scripts are in the `scripts` directory. If you run Linux (or WSL under Windows), you can run these directly:
|
||||||
|
|
||||||
|
- `scripts/check` will check your Python files for linting errors
|
||||||
|
- `scripts/fix` will fix some formatting mistakes automatically
|
||||||
|
|
||||||
|
You can also run these commands manually on Windows:
|
||||||
|
|
||||||
|
##### Check
|
||||||
|
```
|
||||||
|
uv run ruff check
|
||||||
|
uv run ruff format --check
|
||||||
|
uv run pylint custom_components
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Fix
|
||||||
|
```
|
||||||
|
uv run ruff check --fix
|
||||||
|
uv run ruff format
|
||||||
|
```
|
||||||
|
|
||||||
### Docker Compose Development Environment
|
### Docker Compose Development Environment
|
||||||
You can also use the following Docker Compose configuration to automatically start up the latest HA release with the `auth_oidc` integration:
|
You can also use the following Docker Compose configuration to automatically start up the latest HA release with the `auth_oidc` integration:
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2024 Christiaan Goossens
|
Copyright 2024-2025 Christiaan Goossens
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ If you would like to read the background/open letter that lead to this component
|
|||||||
|
|
||||||
## Installation guide
|
## Installation guide
|
||||||
|
|
||||||
1. Add this repository to [HACS](https://hacs.xyz/).
|
1. Add this repository to [HACS](https://hacs.xyz/) (or search for "OpenID Connect" in HACS).
|
||||||
|
|
||||||
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=christiaangoossens&repository=hass-oidc-auth&category=Integration)
|
[](https://my.home-assistant.io/redirect/hacs_repository/?owner=christiaangoossens&repository=hass-oidc-auth&category=Integration)
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from .config import (
|
|||||||
ROLES,
|
ROLES,
|
||||||
NETWORK,
|
NETWORK,
|
||||||
FEATURES_INCLUDE_GROUPS_SCOPE,
|
FEATURES_INCLUDE_GROUPS_SCOPE,
|
||||||
|
FEATURES_FORCE_HTTPS,
|
||||||
)
|
)
|
||||||
|
|
||||||
# pylint: enable=useless-import-alias
|
# pylint: enable=useless-import-alias
|
||||||
@@ -91,10 +92,11 @@ async def async_setup(hass: HomeAssistant, config):
|
|||||||
|
|
||||||
# Register the views
|
# Register the views
|
||||||
name = config[DOMAIN].get(DISPLAY_NAME, DEFAULT_TITLE)
|
name = config[DOMAIN].get(DISPLAY_NAME, DEFAULT_TITLE)
|
||||||
|
force_https = features_config.get(FEATURES_FORCE_HTTPS, False)
|
||||||
|
|
||||||
hass.http.register_view(OIDCWelcomeView(name))
|
hass.http.register_view(OIDCWelcomeView(name))
|
||||||
hass.http.register_view(OIDCRedirectView(oidc_client))
|
hass.http.register_view(OIDCRedirectView(oidc_client, force_https))
|
||||||
hass.http.register_view(OIDCCallbackView(oidc_client, provider))
|
hass.http.register_view(OIDCCallbackView(oidc_client, provider, force_https))
|
||||||
hass.http.register_view(OIDCFinishView())
|
hass.http.register_view(OIDCFinishView())
|
||||||
|
|
||||||
_LOGGER.info("Registered OIDC views")
|
_LOGGER.info("Registered OIDC views")
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ FEATURES_AUTOMATIC_USER_LINKING = "automatic_user_linking"
|
|||||||
FEATURES_AUTOMATIC_PERSON_CREATION = "automatic_person_creation"
|
FEATURES_AUTOMATIC_PERSON_CREATION = "automatic_person_creation"
|
||||||
FEATURES_DISABLE_PKCE = "disable_rfc7636"
|
FEATURES_DISABLE_PKCE = "disable_rfc7636"
|
||||||
FEATURES_INCLUDE_GROUPS_SCOPE = "include_groups_scope"
|
FEATURES_INCLUDE_GROUPS_SCOPE = "include_groups_scope"
|
||||||
|
FEATURES_FORCE_HTTPS = "force_https"
|
||||||
CLAIMS = "claims"
|
CLAIMS = "claims"
|
||||||
CLAIMS_DISPLAY_NAME = "display_name"
|
CLAIMS_DISPLAY_NAME = "display_name"
|
||||||
CLAIMS_USERNAME = "username"
|
CLAIMS_USERNAME = "username"
|
||||||
@@ -69,6 +70,10 @@ CONFIG_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(
|
vol.Optional(
|
||||||
FEATURES_INCLUDE_GROUPS_SCOPE, default=True
|
FEATURES_INCLUDE_GROUPS_SCOPE, default=True
|
||||||
): vol.Coerce(bool),
|
): vol.Coerce(bool),
|
||||||
|
# Force HTTPS on all generated URLs (like redirect_uri)
|
||||||
|
vol.Optional(FEATURES_FORCE_HTTPS, default=False): vol.Coerce(
|
||||||
|
bool
|
||||||
|
),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
# Determine which specific claims will be used from the id_token
|
# Determine which specific claims will be used from the id_token
|
||||||
|
|||||||
@@ -17,10 +17,14 @@ class OIDCCallbackView(HomeAssistantView):
|
|||||||
name = "auth:oidc:callback"
|
name = "auth:oidc:callback"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, oidc_client: OIDCClient, oidc_provider: OpenIDAuthProvider
|
self,
|
||||||
|
oidc_client: OIDCClient,
|
||||||
|
oidc_provider: OpenIDAuthProvider,
|
||||||
|
force_https: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.oidc_client = oidc_client
|
self.oidc_client = oidc_client
|
||||||
self.oidc_provider = oidc_provider
|
self.oidc_provider = oidc_provider
|
||||||
|
self.force_https = force_https
|
||||||
|
|
||||||
async def get(self, request: web.Request) -> web.Response:
|
async def get(self, request: web.Request) -> web.Response:
|
||||||
"""Receive response."""
|
"""Receive response."""
|
||||||
@@ -38,7 +42,7 @@ class OIDCCallbackView(HomeAssistantView):
|
|||||||
)
|
)
|
||||||
return web.Response(text=view_html, content_type="text/html")
|
return web.Response(text=view_html, content_type="text/html")
|
||||||
|
|
||||||
redirect_uri = get_url("/auth/oidc/callback")
|
redirect_uri = get_url("/auth/oidc/callback", self.force_https)
|
||||||
user_details = await self.oidc_client.async_complete_token_flow(
|
user_details = await self.oidc_client.async_complete_token_flow(
|
||||||
redirect_uri, code, state
|
redirect_uri, code, state
|
||||||
)
|
)
|
||||||
@@ -63,4 +67,6 @@ class OIDCCallbackView(HomeAssistantView):
|
|||||||
return web.Response(text=view_html, content_type="text/html")
|
return web.Response(text=view_html, content_type="text/html")
|
||||||
|
|
||||||
code = await self.oidc_provider.async_save_user_info(user_details)
|
code = await self.oidc_provider.async_save_user_info(user_details)
|
||||||
return web.HTTPFound(get_url("/auth/oidc/finish?code=" + code))
|
return web.HTTPFound(
|
||||||
|
get_url("/auth/oidc/finish?code=" + code, self.force_https)
|
||||||
|
)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class OIDCFinishView(HomeAssistantView):
|
|||||||
|
|
||||||
# Return redirect to the main page for sign in with a cookie
|
# Return redirect to the main page for sign in with a cookie
|
||||||
return web.HTTPFound(
|
return web.HTTPFound(
|
||||||
location="/",
|
location="/?storeToken=true",
|
||||||
headers={
|
headers={
|
||||||
# Set a cookie to enable autologin on only the specific path used
|
# Set a cookie to enable autologin on only the specific path used
|
||||||
# for the POST request, with all strict parameters set
|
# for the POST request, with all strict parameters set
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ class OIDCRedirectView(HomeAssistantView):
|
|||||||
url = PATH
|
url = PATH
|
||||||
name = "auth:oidc:redirect"
|
name = "auth:oidc:redirect"
|
||||||
|
|
||||||
def __init__(self, oidc_client: OIDCClient) -> None:
|
def __init__(self, oidc_client: OIDCClient, force_https: bool) -> None:
|
||||||
self.oidc_client = oidc_client
|
self.oidc_client = oidc_client
|
||||||
|
self.force_https = force_https
|
||||||
|
|
||||||
async def get(self, _: web.Request) -> web.Response:
|
async def get(self, _: web.Request) -> web.Response:
|
||||||
"""Receive response."""
|
"""Receive response."""
|
||||||
|
|
||||||
redirect_uri = get_url("/auth/oidc/callback")
|
redirect_uri = get_url("/auth/oidc/callback", self.force_https)
|
||||||
auth_url = await self.oidc_client.async_get_authorization_url(redirect_uri)
|
auth_url = await self.oidc_client.async_get_authorization_url(redirect_uri)
|
||||||
|
|
||||||
if auth_url:
|
if auth_url:
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ from homeassistant.components import http
|
|||||||
from .views.loader import AsyncTemplateRenderer
|
from .views.loader import AsyncTemplateRenderer
|
||||||
|
|
||||||
|
|
||||||
def get_url(path: str) -> str:
|
def get_url(path: str, force_https: bool) -> str:
|
||||||
"""Returns the requested path appended to the current request base URL."""
|
"""Returns the requested path appended to the current request base URL."""
|
||||||
if (req := http.current_request.get()) is None:
|
if (req := http.current_request.get()) is None:
|
||||||
raise RuntimeError("No current request in context")
|
raise RuntimeError("No current request in context")
|
||||||
|
|
||||||
base_uri = str(req.url).split("/auth", 2)[0]
|
base_uri = str(req.url).split("/auth", 2)[0]
|
||||||
|
if force_https:
|
||||||
|
base_uri = base_uri.replace("http://", "https://")
|
||||||
return f"{base_uri}{path}"
|
return f"{base_uri}{path}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"auth",
|
"auth",
|
||||||
"http"
|
"http"
|
||||||
],
|
],
|
||||||
"documentation": "https://github.com/christiaangoossens/hass-oidc-auth",
|
"documentation": "https://github.com/christiaangoossens/hass-oidc-auth/blob/v0.6.3-alpha/docs/configuration.md",
|
||||||
"integration_type": "service",
|
"integration_type": "service",
|
||||||
"iot_class": "calculated",
|
"iot_class": "calculated",
|
||||||
"issue_tracker": "https://github.com/christiaangoossens/hass-oidc-auth/issues",
|
"issue_tracker": "https://github.com/christiaangoossens/hass-oidc-auth/issues",
|
||||||
@@ -19,5 +19,5 @@
|
|||||||
"jinja2>=3.1.4",
|
"jinja2>=3.1.4",
|
||||||
"bcrypt>=4.2.0"
|
"bcrypt>=4.2.0"
|
||||||
],
|
],
|
||||||
"version": "0.6.2"
|
"version": "0.6.3"
|
||||||
}
|
}
|
||||||
@@ -74,6 +74,28 @@ auth_oidc:
|
|||||||
|
|
||||||
This will show the provider on the login screen as: "Login with Example".
|
This will show the provider on the login screen as: "Login with Example".
|
||||||
|
|
||||||
|
### Forcing HTTPS
|
||||||
|
First check if you are setting the header `X-Forwarded-Proto` in your proxy and if the [proxy settings for Home Assistant](https://www.home-assistant.io/integrations/http/#use_x_forwarded_for) are configured correctly. You should also check if IP addresses in your logs actually match the origin IP (instead of proxy IP). If you cannot find any mistakes, you may use the following config option to force HTTPS regardless:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
auth_oidc:
|
||||||
|
features:
|
||||||
|
force_https: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disabling registration for new users
|
||||||
|
This integration does not allow disabling registration for new users, as there is no way to abort registration that late in the process while providing a good user experience.
|
||||||
|
You can however set both roles to groups that only contain certain users or to a non-existant group.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
auth_oidc:
|
||||||
|
roles:
|
||||||
|
user: "non_existent"
|
||||||
|
admin: "admins"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that if you put both on non-existent groups, no users will be able to login.
|
||||||
|
|
||||||
### Migrating from HA username/password users to OIDC users
|
### Migrating from HA username/password users to OIDC users
|
||||||
If you already have users created within Home Assistant and would like to re-use the current user profile for your OIDC login, you can (temporarily) enable `features.automatic_user_linking`, with the following config (example):
|
If you already have users created within Home Assistant and would like to re-use the current user profile for your OIDC login, you can (temporarily) enable `features.automatic_user_linking`, with the following config (example):
|
||||||
|
|
||||||
@@ -93,6 +115,8 @@ Upon login, OIDC users will then automatically be linked to the HA user with the
|
|||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> MFA is ignored when using this setting, thus bypassing any MFA configuration the user has originally configured, as long as the username is an exact match. This is dangerous if you are not aware of it!
|
> MFA is ignored when using this setting, thus bypassing any MFA configuration the user has originally configured, as long as the username is an exact match. This is dangerous if you are not aware of it!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Using a private certificate authority
|
### Using a private certificate authority
|
||||||
If you use a private certificate authority to secure your OIDC provider, you must configure the root certificates of your private certificate authority. Otherwise you will get an error (`[SSL: CERTIFICATE_VERIFY_FAILED]`) when connecting to the OIDC provider.
|
If you use a private certificate authority to secure your OIDC provider, you must configure the root certificates of your private certificate authority. Otherwise you will get an error (`[SSL: CERTIFICATE_VERIFY_FAILED]`) when connecting to the OIDC provider.
|
||||||
|
|
||||||
@@ -132,6 +156,7 @@ Here's a table of all options that you can set:
|
|||||||
| `features.automatic_person_creation` | `boolean` | No | `true` | Automatically creates a person entry for new user profiles created by this integration. Recommended if you would like to assign presence detection to OIDC users. |
|
| `features.automatic_person_creation` | `boolean` | No | `true` | Automatically creates a person entry for new user profiles created by this integration. Recommended if you would like to assign presence detection to OIDC users. |
|
||||||
| `features.disable_rfc7636` | `boolean`| No | `false` | Disables PKCE (RFC 7636) for OIDC providers that don't support it. You should not need this with most providers. |
|
| `features.disable_rfc7636` | `boolean`| No | `false` | Disables PKCE (RFC 7636) for OIDC providers that don't support it. You should not need this with most providers. |
|
||||||
| `features.include_groups_scope` | `boolean` | No | `true` | Include the 'groups' scope in the OIDC request. Set to `false` to exclude it. |
|
| `features.include_groups_scope` | `boolean` | No | `true` | Include the 'groups' scope in the OIDC request. Set to `false` to exclude it. |
|
||||||
|
| `features.force_https` | `boolean` | No | `false` | Set to `true` to force all URLs generated to use `https` instead of automatically determining based on the request scheme or `X-Forwarded-Proto`. |
|
||||||
| `claims.display_name` | `string` | No | `name` | The claim to use to obtain the display name.
|
| `claims.display_name` | `string` | No | `name` | The claim to use to obtain the display name.
|
||||||
| `claims.username` | `string` | No | `preferred_username` | The claim to use to obtain the username.
|
| `claims.username` | `string` | No | `preferred_username` | The claim to use to obtain the username.
|
||||||
| `claims.groups` | `string` | No | `groups` | The claim to use to obtain the user's group(s). |
|
| `claims.groups` | `string` | No | `groups` | The claim to use to obtain the user's group(s). |
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Microsoft Entra ID
|
# Microsoft Entra ID
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Microsoft Entra ID does not support public clients that are not Single Page Applications (SPA's). Therefore, you will have to use a client secret.
|
> Microsoft Entra ID does not support public clients that are not Single Page Applications (SPA's). Therefore, you will have to use a client secret.
|
||||||
|
## Basic configuration
|
||||||
1. Go to app registrations in Entra ID.
|
1. Go to app registrations in Entra ID.
|
||||||
2. Create a new app, use the "Web" type for the redirect URI and fill in your URL: `<ha url>/auth/oidc/callback`. Note that you either have to use localhost, or HTTPS.
|
2. Create a new app, use the "Web" type for the redirect URI and fill in your URL: `<ha url>/auth/oidc/callback`. Note that you either have to use localhost, or HTTPS.
|
||||||
3. Copy the 'Application (client) ID' on the overview page of your app and use it as your `client_id`.
|
3. Copy the 'Application (client) ID' on the overview page of your app and use it as your `client_id`.
|
||||||
@@ -25,3 +25,27 @@ auth_oidc:
|
|||||||
|
|
||||||
> [!CAUTION]
|
> [!CAUTION]
|
||||||
> Be careful! Configuring Entra ID wrong may leave your Home Assistant install open for anyone with a Microsoft account. Please use "Single tenant" account types only. Do not enable "Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)" or personal account modes without enabling the mode to only allow specific accounts first!
|
> Be careful! Configuring Entra ID wrong may leave your Home Assistant install open for anyone with a Microsoft account. Please use "Single tenant" account types only. Do not enable "Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant)" or personal account modes without enabling the mode to only allow specific accounts first!
|
||||||
|
|
||||||
|
## Configuring user roles
|
||||||
|
If you like to configure the Home Assistant users roles based on your Entra ID settings, you have to create 2 roles within your Entra ID app registration.
|
||||||
|
Go to "App registrations" and select app roles. Create two new roles for admins and users, giving them sensible names and values (the example uses `users` and `admins`), that you will need later in your HA configuration.
|
||||||
|
|
||||||
|
<img width="1205" height="965" alt="Entra-HA-Roles" src="https://github.com/user-attachments/assets/568a1526-0607-4f88-945f-7c4f1fcc0ac2" />
|
||||||
|
|
||||||
|
Then you need to create the users and assign them a role of your choice.
|
||||||
|
Go to "Enterprise apps" chose your app registration again and select "Users and groups" within the manage section. Add users, or groups from your tenant or AD-sync and assign them a role, from the ones you created before.
|
||||||
|
|
||||||
|
<img width="1112" height="570" alt="Entra-HA-Users" src="https://github.com/user-attachments/assets/13a49cee-798b-4b53-8fee-d2792ccd7763" />
|
||||||
|
|
||||||
|
Last thing to do is to include
|
||||||
|
```
|
||||||
|
claims:
|
||||||
|
groups: "roles"
|
||||||
|
roles:
|
||||||
|
admin: "admins"
|
||||||
|
user: "users"
|
||||||
|
```
|
||||||
|
in your auth_oidc config, where the roles values correspond to the ones you chose in your Entra ID roles.
|
||||||
|
Make sure, you keep the "include_groups_scope: False" from the basic configuration, as the claim needed for Entra ID is "roles".
|
||||||
|
|
||||||
|
Newly created users will get the role assigned in Entra ID, but there is no update to user roles. A user created with user role in HA will not get the admin role, if you change the assignment later on in Entra ID.
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
"name": "OpenID Connect",
|
"name": "OpenID Connect",
|
||||||
"hide_default_branch": true,
|
"hide_default_branch": true,
|
||||||
"render_readme": true,
|
"render_readme": true,
|
||||||
"homeassistant": "2024.12"
|
"homeassistant": "2025.08"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "hass-oidc-auth"
|
name = "hass-oidc-auth"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
description = "OIDC component for Home Assistant"
|
description = "OIDC component for Home Assistant"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Christiaan Goossens", email = "contact@christiaangoossens.nl" }
|
{ name = "Christiaan Goossens", email = "contact@christiaangoossens.nl" }
|
||||||
@@ -13,30 +13,22 @@ dependencies = [
|
|||||||
"bcrypt>=4.2.0",
|
"bcrypt>=4.2.0",
|
||||||
]
|
]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">= 3.13"
|
requires-python = ">= 3.13.2"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
[tool.rye]
|
[tool.uv]
|
||||||
managed = true
|
managed = true
|
||||||
dev-dependencies = [
|
dev-dependencies = [
|
||||||
"homeassistant~=2024.12",
|
"homeassistant~=2025.8",
|
||||||
"pylint~=3.3",
|
"pylint~=3.3",
|
||||||
|
"ruff>=0.12.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.hatch.metadata]
|
[tool.hatch.metadata]
|
||||||
allow-direct-references = true
|
allow-direct-references = true
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["custom_components/auth_oidc"]
|
packages = ["custom_components/auth_oidc"]
|
||||||
|
|
||||||
[tool.rye.scripts]
|
|
||||||
check = { chain = ["check-lint", "check-fmt", "check-pylint" ] }
|
|
||||||
"check-lint" = "rye lint"
|
|
||||||
"check-fmt" = "rye fmt --check"
|
|
||||||
"check-pylint" = "pylint custom_components"
|
|
||||||
fix = { chain = ["fix-lint", "fix-fmt" ] }
|
|
||||||
"fix-lint" = "rye lint --fix"
|
|
||||||
"fix-fmt" = "rye fmt"
|
|
||||||
@@ -14,11 +14,16 @@
|
|||||||
],
|
],
|
||||||
"prCreation": "immediate"
|
"prCreation": "immediate"
|
||||||
},
|
},
|
||||||
|
"lockFileMaintenance": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
"packageRules": [
|
"packageRules": [
|
||||||
{
|
{
|
||||||
"description": "Group all GitHub Actions updates",
|
"description": "Group all GitHub Actions updates",
|
||||||
"matchDatasources": [
|
"matchDatasources": [
|
||||||
"github-actions"
|
"github-actions",
|
||||||
|
"github-tags",
|
||||||
|
"github-runners"
|
||||||
],
|
],
|
||||||
"groupName": "Github Actions Updates",
|
"groupName": "Github Actions Updates",
|
||||||
"automerge": true
|
"automerge": true
|
||||||
@@ -34,7 +39,7 @@
|
|||||||
"automerge": false
|
"automerge": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Version updates for other pip packages",
|
"description": "Version updates for other Python packages",
|
||||||
"matchDatasources": [
|
"matchDatasources": [
|
||||||
"pypi"
|
"pypi"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,286 +0,0 @@
|
|||||||
# generated by rye
|
|
||||||
# use `rye lock` or `rye sync` to update this lockfile
|
|
||||||
#
|
|
||||||
# last locked with the following flags:
|
|
||||||
# pre: false
|
|
||||||
# features: []
|
|
||||||
# all-features: false
|
|
||||||
# with-sources: false
|
|
||||||
# generate-hashes: false
|
|
||||||
# universal: false
|
|
||||||
|
|
||||||
-e file:.
|
|
||||||
acme==3.0.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
aiodns==3.2.0
|
|
||||||
# via homeassistant
|
|
||||||
aiofiles==24.1.0
|
|
||||||
# via hass-oidc-auth
|
|
||||||
aiohappyeyeballs==2.4.4
|
|
||||||
# via aiohttp
|
|
||||||
aiohasupervisor==0.2.1
|
|
||||||
# via homeassistant
|
|
||||||
aiohttp==3.11.11
|
|
||||||
# via aiohasupervisor
|
|
||||||
# via aiohttp-cors
|
|
||||||
# via aiohttp-fast-zlib
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
# via snitun
|
|
||||||
aiohttp-cors==0.7.0
|
|
||||||
# via homeassistant
|
|
||||||
aiohttp-fast-zlib==0.2.0
|
|
||||||
# via homeassistant
|
|
||||||
aiooui==0.1.7
|
|
||||||
# via bluetooth-adapters
|
|
||||||
aiosignal==1.3.2
|
|
||||||
# via aiohttp
|
|
||||||
aiozoneinfo==0.2.1
|
|
||||||
# via homeassistant
|
|
||||||
anyio==4.7.0
|
|
||||||
# via httpx
|
|
||||||
astral==2.2
|
|
||||||
# via homeassistant
|
|
||||||
astroid==3.3.8
|
|
||||||
# via pylint
|
|
||||||
async-interrupt==1.2.0
|
|
||||||
# via habluetooth
|
|
||||||
# via homeassistant
|
|
||||||
async-timeout==5.0.1
|
|
||||||
# via snitun
|
|
||||||
atomicwrites-homeassistant==1.4.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
attrs==24.2.0
|
|
||||||
# via aiohttp
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
# via snitun
|
|
||||||
audioop-lts==0.2.1
|
|
||||||
# via homeassistant
|
|
||||||
# via standard-aifc
|
|
||||||
awesomeversion==24.6.0
|
|
||||||
# via homeassistant
|
|
||||||
bcrypt==4.2.0
|
|
||||||
# via hass-oidc-auth
|
|
||||||
# via homeassistant
|
|
||||||
bleak==0.22.3
|
|
||||||
# via bleak-retry-connector
|
|
||||||
# via bluetooth-adapters
|
|
||||||
# via habluetooth
|
|
||||||
bleak-retry-connector==3.6.0
|
|
||||||
# via habluetooth
|
|
||||||
bluetooth-adapters==0.20.2
|
|
||||||
# via bleak-retry-connector
|
|
||||||
# via bluetooth-auto-recovery
|
|
||||||
# via habluetooth
|
|
||||||
bluetooth-auto-recovery==1.4.2
|
|
||||||
# via habluetooth
|
|
||||||
bluetooth-data-tools==1.20.0
|
|
||||||
# via habluetooth
|
|
||||||
boto3==1.35.87
|
|
||||||
# via pycognito
|
|
||||||
botocore==1.35.87
|
|
||||||
# via boto3
|
|
||||||
# via s3transfer
|
|
||||||
btsocket==0.3.0
|
|
||||||
# via bluetooth-auto-recovery
|
|
||||||
certifi==2024.12.14
|
|
||||||
# via homeassistant
|
|
||||||
# via httpcore
|
|
||||||
# via httpx
|
|
||||||
# via requests
|
|
||||||
cffi==1.17.1
|
|
||||||
# via cryptography
|
|
||||||
# via pycares
|
|
||||||
charset-normalizer==3.4.0
|
|
||||||
# via requests
|
|
||||||
ciso8601==2.3.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
cryptography==43.0.1
|
|
||||||
# via acme
|
|
||||||
# via bluetooth-data-tools
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
# via josepy
|
|
||||||
# via pyjwt
|
|
||||||
# via pyopenssl
|
|
||||||
# via securetar
|
|
||||||
# via snitun
|
|
||||||
dbus-fast==2.24.4
|
|
||||||
# via bleak
|
|
||||||
# via bleak-retry-connector
|
|
||||||
# via bluetooth-adapters
|
|
||||||
dill==0.3.9
|
|
||||||
# via pylint
|
|
||||||
ecdsa==0.19.0
|
|
||||||
# via python-jose
|
|
||||||
envs==1.4
|
|
||||||
# via pycognito
|
|
||||||
fnv-hash-fast==1.0.2
|
|
||||||
# via homeassistant
|
|
||||||
fnvhash==0.1.0
|
|
||||||
# via fnv-hash-fast
|
|
||||||
frozenlist==1.5.0
|
|
||||||
# via aiohttp
|
|
||||||
# via aiosignal
|
|
||||||
h11==0.14.0
|
|
||||||
# via httpcore
|
|
||||||
habluetooth==3.6.0
|
|
||||||
# via home-assistant-bluetooth
|
|
||||||
hass-nabucasa==0.86.0
|
|
||||||
# via homeassistant
|
|
||||||
home-assistant-bluetooth==1.13.0
|
|
||||||
# via homeassistant
|
|
||||||
homeassistant==2024.12.5
|
|
||||||
httpcore==1.0.7
|
|
||||||
# via httpx
|
|
||||||
httpx==0.27.2
|
|
||||||
# via homeassistant
|
|
||||||
idna==3.10
|
|
||||||
# via anyio
|
|
||||||
# via httpx
|
|
||||||
# via requests
|
|
||||||
# via yarl
|
|
||||||
ifaddr==0.2.0
|
|
||||||
# via homeassistant
|
|
||||||
isort==5.13.2
|
|
||||||
# via pylint
|
|
||||||
jinja2==3.1.4
|
|
||||||
# via hass-oidc-auth
|
|
||||||
# via homeassistant
|
|
||||||
jmespath==1.0.1
|
|
||||||
# via boto3
|
|
||||||
# via botocore
|
|
||||||
josepy==1.14.0
|
|
||||||
# via acme
|
|
||||||
lru-dict==1.3.0
|
|
||||||
# via homeassistant
|
|
||||||
markupsafe==3.0.2
|
|
||||||
# via jinja2
|
|
||||||
mashumaro==3.15
|
|
||||||
# via aiohasupervisor
|
|
||||||
# via webrtc-models
|
|
||||||
mccabe==0.7.0
|
|
||||||
# via pylint
|
|
||||||
multidict==6.1.0
|
|
||||||
# via aiohttp
|
|
||||||
# via yarl
|
|
||||||
orjson==3.10.12
|
|
||||||
# via aiohasupervisor
|
|
||||||
# via homeassistant
|
|
||||||
# via webrtc-models
|
|
||||||
packaging==24.2
|
|
||||||
# via homeassistant
|
|
||||||
pillow==11.0.0
|
|
||||||
# via homeassistant
|
|
||||||
platformdirs==4.3.6
|
|
||||||
# via pylint
|
|
||||||
propcache==0.2.1
|
|
||||||
# via aiohttp
|
|
||||||
# via homeassistant
|
|
||||||
# via yarl
|
|
||||||
psutil==6.1.1
|
|
||||||
# via psutil-home-assistant
|
|
||||||
psutil-home-assistant==0.0.1
|
|
||||||
# via homeassistant
|
|
||||||
pyasn1==0.6.1
|
|
||||||
# via python-jose
|
|
||||||
# via rsa
|
|
||||||
pycares==4.5.0
|
|
||||||
# via aiodns
|
|
||||||
pycognito==2024.5.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
pycparser==2.22
|
|
||||||
# via cffi
|
|
||||||
pyjwt==2.10.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
# via pycognito
|
|
||||||
pylint==3.3.3
|
|
||||||
pyopenssl==24.2.1
|
|
||||||
# via acme
|
|
||||||
# via homeassistant
|
|
||||||
# via josepy
|
|
||||||
pyrfc3339==2.0.1
|
|
||||||
# via acme
|
|
||||||
pyric==0.1.6.3
|
|
||||||
# via bluetooth-auto-recovery
|
|
||||||
python-dateutil==2.9.0.post0
|
|
||||||
# via botocore
|
|
||||||
python-jose==3.3.0
|
|
||||||
# via hass-oidc-auth
|
|
||||||
python-slugify==8.0.4
|
|
||||||
# via homeassistant
|
|
||||||
pytz==2024.2
|
|
||||||
# via acme
|
|
||||||
# via astral
|
|
||||||
pyyaml==6.0.2
|
|
||||||
# via homeassistant
|
|
||||||
requests==2.32.3
|
|
||||||
# via acme
|
|
||||||
# via homeassistant
|
|
||||||
# via pycognito
|
|
||||||
rsa==4.9
|
|
||||||
# via python-jose
|
|
||||||
s3transfer==0.10.4
|
|
||||||
# via boto3
|
|
||||||
securetar==2024.11.0
|
|
||||||
# via homeassistant
|
|
||||||
setuptools==75.6.0
|
|
||||||
# via acme
|
|
||||||
six==1.17.0
|
|
||||||
# via ecdsa
|
|
||||||
# via python-dateutil
|
|
||||||
sniffio==1.3.1
|
|
||||||
# via anyio
|
|
||||||
# via httpx
|
|
||||||
snitun==0.39.1
|
|
||||||
# via hass-nabucasa
|
|
||||||
sqlalchemy==2.0.36
|
|
||||||
# via homeassistant
|
|
||||||
standard-aifc==3.13.0
|
|
||||||
# via homeassistant
|
|
||||||
standard-chunk==3.13.0
|
|
||||||
# via standard-aifc
|
|
||||||
standard-telnetlib==3.13.0
|
|
||||||
# via homeassistant
|
|
||||||
text-unidecode==1.3
|
|
||||||
# via python-slugify
|
|
||||||
tomlkit==0.13.2
|
|
||||||
# via pylint
|
|
||||||
typing-extensions==4.12.2
|
|
||||||
# via homeassistant
|
|
||||||
# via mashumaro
|
|
||||||
# via sqlalchemy
|
|
||||||
tzdata==2024.2
|
|
||||||
# via aiozoneinfo
|
|
||||||
uart-devices==0.1.0
|
|
||||||
# via bluetooth-adapters
|
|
||||||
ulid-transform==1.0.2
|
|
||||||
# via homeassistant
|
|
||||||
urllib3==1.26.20
|
|
||||||
# via botocore
|
|
||||||
# via homeassistant
|
|
||||||
# via requests
|
|
||||||
usb-devices==0.4.5
|
|
||||||
# via bluetooth-adapters
|
|
||||||
# via bluetooth-auto-recovery
|
|
||||||
uv==0.5.4
|
|
||||||
# via homeassistant
|
|
||||||
voluptuous==0.15.2
|
|
||||||
# via homeassistant
|
|
||||||
# via voluptuous-openapi
|
|
||||||
# via voluptuous-serialize
|
|
||||||
voluptuous-openapi==0.0.5
|
|
||||||
# via homeassistant
|
|
||||||
voluptuous-serialize==2.6.0
|
|
||||||
# via homeassistant
|
|
||||||
webrtc-models==0.3.0
|
|
||||||
# via hass-nabucasa
|
|
||||||
# via homeassistant
|
|
||||||
yarl==1.18.3
|
|
||||||
# via aiohasupervisor
|
|
||||||
# via aiohttp
|
|
||||||
# via homeassistant
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# generated by rye
|
|
||||||
# use `rye lock` or `rye sync` to update this lockfile
|
|
||||||
#
|
|
||||||
# last locked with the following flags:
|
|
||||||
# pre: false
|
|
||||||
# features: []
|
|
||||||
# all-features: false
|
|
||||||
# with-sources: false
|
|
||||||
# generate-hashes: false
|
|
||||||
# universal: false
|
|
||||||
|
|
||||||
-e file:.
|
|
||||||
aiofiles==24.1.0
|
|
||||||
# via hass-oidc-auth
|
|
||||||
bcrypt==4.2.1
|
|
||||||
# via hass-oidc-auth
|
|
||||||
ecdsa==0.19.0
|
|
||||||
# via python-jose
|
|
||||||
jinja2==3.1.5
|
|
||||||
# via hass-oidc-auth
|
|
||||||
markupsafe==3.0.2
|
|
||||||
# via jinja2
|
|
||||||
pyasn1==0.6.1
|
|
||||||
# via python-jose
|
|
||||||
# via rsa
|
|
||||||
python-jose==3.3.0
|
|
||||||
# via hass-oidc-auth
|
|
||||||
rsa==4.9
|
|
||||||
# via python-jose
|
|
||||||
six==1.17.0
|
|
||||||
# via ecdsa
|
|
||||||
4
scripts/check
Executable file
4
scripts/check
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
uv run ruff check
|
||||||
|
uv run ruff format --check
|
||||||
|
uv run pylint custom_components
|
||||||
3
scripts/fix
Executable file
3
scripts/fix
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
uv run ruff check --fix
|
||||||
|
uv run ruff format
|
||||||
2
scripts/sync
Executable file
2
scripts/sync
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
uv sync --locked
|
||||||
Reference in New Issue
Block a user