Skip to content

Feat: Add authentik idp#8619

Open
Maddosaurus wants to merge 13 commits into
SSSD:masterfrom
Maddosaurus:feat-authentik
Open

Feat: Add authentik idp#8619
Maddosaurus wants to merge 13 commits into
SSSD:masterfrom
Maddosaurus:feat-authentik

Conversation

@Maddosaurus

@Maddosaurus Maddosaurus commented Apr 20, 2026

Copy link
Copy Markdown

This PR add Authentik as an available IDP provider besides Entra and Keycloak.

From a quick look around the Authentik repo, it looks they do daily test runs against their Compose deployment (see this workflow).

For testing, starting from a fresh Authentik instance (Docker compose instructions), the following additional configuration is needed:

  • Create a default device flow: Authentik Docs
  • Create a new OAuth Client:
    • Navigate to the Admin Interface
    • Applications -> Providers -> Create -> Oauth2/OpenID Provider
      • Set a provider name (e.g. sssd-prod-prov) and auth flow (e.g. default-provider-authorization-implicit-consent (Authorize Application))
      • Open "Advanced protocol settings" and add the scope authentik default OAuth Mapping: authentik API access to "Selected Scopes"
      • Create Provider
    • Applications -> Applications -> Create
      • Create a slug (e.g. sssd-prod-app and select the previously created provider (e.g. sssd-prod-prov)
      • Create Application
    • Authentik creates a service account for this application if the device flow is used for the first time ([docs](https://docs.goauthentik.io/add-secure-apps/providers/oauth2/machine_to_machine/#automatic-service-account-creation)), so let's get this created:
      • Start sssd with the new config and let it run - you likely get a 400. SSSD can be stopped.
      • It will have created a new service account (naming schema: ak-<application>-client_credentials)
    • Open the newly created Application, navigate to "Policy/Group/User bindings", select "Bind existing...", switch to "User" and select the autogenerated user for your application (e.g. "ak-sssd-prod-prov-client_credentials"), and select "Create"
    • Create a role to allow reading of users and groups: Directory -> Roles -> Create
      • Give it a name (e.g. authentik user goup read-only)
      • Open the created group -> Permissions -> Assign Permission
        • Under authentik Core select Can view Group and Can view User
      • Assign the Role to the ak service user of your application: Users -> $serviceaccout -> Roles -> Add to existing role -> select the created role

Combined with the following sssd.conf this will result in a running setup for ssh login and sudo management:

[domain/authentik]
id_provider = idp
idp_type = authentik:https://authentik.company/api/v3/core/
idp_client_id = myclient
idp_client_secret = YOUR-CLIENT-SCERET
idp_token_endpoint = https://authentik.company/application/o/token/
idp_userinfo_endpoint = https://authentik.company/application/o/userinfo/
idp_device_auth_endpoint = https://authentik.company/application/o/device/
idp_id_scope = goauthentik.io/api
idp_auth_scope = openid profile email offline_access

Note that authentik does not have application-specific endpoints for token, userinfo and device auth, but instead global endpoints. For example, the token endpoint for a given Authentik server would be https://prod.idp.tld.com/application/o/token (only authentik.company is a placeholder in this config).

Fixes #8613

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Authentik as an Identity Provider (IdP) in SSSD, including documentation, a new lookup implementation, and JSON parsing enhancements. Several critical issues were identified in the review: a syntax error due to missing parentheses in a conditional check, incorrect parameter types and redundant calls during URL encoding of device codes, and logic errors in identifying Authentik users and groups. Specifically, using 'pk' for both user and group identifiers prevents proper object differentiation, and the user lookup logic should be updated to check for the 'pk' attribute to align with Authentik's API.

Comment thread src/oidc_child/oidc_child_id.c Outdated
Comment thread src/oidc_child/oidc_child_json.c Outdated
Comment thread src/oidc_child/oidc_child_json.c Outdated
Comment thread src/providers/idp/idp_id_eval.c
@alexey-tikhonov alexey-tikhonov added the no-backport This should go to target branch only. label Apr 20, 2026
@alexey-tikhonov

Copy link
Copy Markdown
Member

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for Authentik as an Identity Provider, including documentation, a new lookup implementation, and enhanced JSON parsing. Feedback points out a potential crash in parse_result due to a missing NULL check when encoding the device_code and a typo in store_json_user where uid was used instead of uuid.

Comment thread src/oidc_child/oidc_child_json.c Outdated
Comment thread src/providers/idp/idp_id_eval.c
@alexey-tikhonov alexey-tikhonov added the coverity Trigger a coverity scan label Apr 20, 2026
Comment thread src/oidc_child/oidc_child_id.c Dismissed
Comment thread src/oidc_child/oidc_child_id.c Outdated
sssd-bot

This comment was marked as outdated.

@alexey-tikhonov

Copy link
Copy Markdown
Member

Review done using Claude Code / claude-opus-4-6

@Maddosaurus, take this with a grain of salt as some points might be off.

If you prefer, feel free to postpone addressing this until somebody from maintainers performs a review.
But if you are willing to read thru and address what makes sense, then you're welcome.

Comment thread src/oidc_child/oidc_child.c Outdated
@Maddosaurus

Copy link
Copy Markdown
Author

@alexey-tikhonov I'd appreciate a human review at this point, as it seems that recent changes on master resulted in this code not working when rebased against the latest master.
I'd be grateful for some pointers about the latest changes with regards to token handling and caching, as I suspect that to be the reason this PR stopped working.
Thanks :)

@alexey-tikhonov

Copy link
Copy Markdown
Member

Could you please rebase on the top of the current 'master' branch?

@Maddosaurus

Copy link
Copy Markdown
Author

I've rebased on master - to describe the current situation:
In the auth flow, SSSD correctly displays the device code & URL and waits for the user to click the link ("Press ENTER to continue"). When clicking the link and then pressing enter, the flow fails with the following log entries:

(2026-04-23 09:32:12): [oidc_child[2461436]] [parse_result] (0x0040): [RID#8] Failed to parse json data on line [1]: [invalid escape].
(2026-04-23 09:32:12): [oidc_child[2461436]] [main] (0x0040): [RID#8] Failed to parse device code reply.
(2026-04-23 09:32:12): [oidc_child[2461436]] [main] (0x3f7c0): [RID#8] oidc_child failed!
(2026-04-23 09:32:12): [be[atikdev]] [eval_access_token_buf] (0x0040): [RID#8] Missing input.
(2026-04-23 09:32:12): [be[atikdev]] [idp_auth_done] (0x0040): [RID#8] Failed to evaluate IdP reply.
(2026-04-23 09:32:12): [be[atikdev]] [child_sig_handler] (0x0020): [RID#8] child [2461436] failed with status [1].

Authentik uses random special characters for the device code, and loading/saving the JSON object in SSSD via the jansson lib strips some of the escaping. I suspect that the device code needs to be url sanitized when loaded from the buffer (eval_access_token_buf). Do you have a recommendation how to do that correctly in this codebase?

I suspect a3c506d to be one of the reasons for a change in behaviour.

This escaping of my change is not needed anymore because of improved URL data escaping, I will remove that.

@alexey-tikhonov

Copy link
Copy Markdown
Member

This currently doesn't build:

src/oidc_child/oidc_child.c: In function ‘main’:
src/oidc_child/oidc_child.c:724:15: error: too few arguments to function ‘parse_result’; expected 2, have 1
  724 |         ret = parse_result(dc_ctx);
      |               ^~~~~~~~~~~~
In file included from src/oidc_child/oidc_child.c:31:
./src/oidc_child/oidc_child_util.h:138:9: note: declared here
  138 | errno_t parse_result(struct devicecode_ctx *dc_ctx, char *idp_type);
      |         ^~~~~~~~~~~~

@Maddosaurus

Maddosaurus commented Apr 23, 2026

Copy link
Copy Markdown
Author

I've removed the not needed function I mentioned earlier.
In this state, the code still produces the error in the logs I showed in my comment
#8619 (comment), which I marked here in the diff.

Could you advise what the best strategy would be to ensure proper url safe encoding of the token that is stored in buf and used in eval_access_token_buf?
I suspect that storing and/or loading the token (which was recently introduced) strips any escape sequences the device token might have had initially.

An example device token that Authentik returns:

<5'X!eDqr,Y5"Kt/]+tlIkc|X^%Xe7[qxA`:hz{LRQ|n~HUlBFG<"&e<yuk$}cYlnr}VVZo%HN*ff%=o&[vp,k2O,Bexgb++g`<vbY<K{cy6._0X_;)hj8@l*2~ZUzK*

@sumit-bose

Copy link
Copy Markdown
Contributor

I've removed the not needed function I mentioned earlier. In this state, the code still produces the error in the logs I showed in my comment #8619 (comment), which I marked here in the diff.

Could you advise what the best strategy would be to ensure proper url safe encoding of the token that is stored in buf and used in eval_access_token_buf? I suspect that storing and/or loading the token (which was recently introduced) strips any escape sequences the device token might have had initially.

An example device token that Authentik returns:

<5'X!eDqr,Y5"Kt/]+tlIkc|X^%Xe7[qxA`:hz{LRQ|n~HUlBFG<"&e<yuk$}cYlnr}VVZo%HN*ff%=o&[vp,k2O,Bexgb++g`<vbY<K{cy6._0X_;)hj8@l*2~ZUzK*

I've removed the not needed function I mentioned earlier. In this state, the code still produces the error in the logs I showed in my comment #8619 (comment), which I marked here in the diff.

Could you advise what the best strategy would be to ensure proper url safe encoding of the token that is stored in buf and used in eval_access_token_buf? I suspect that storing and/or loading the token (which was recently introduced) strips any escape sequences the device token might have had initially.

An example device token that Authentik returns:

<5'X!eDqr,Y5"Kt/]+tlIkc|X^%Xe7[qxA`:hz{LRQ|n~HUlBFG<"&e<yuk$}cYlnr}VVZo%HN*ff%=o&[vp,k2O,Bexgb++g`<vbY<K{cy6._0X_;)hj8@l*2~ZUzK*

Hi,

I'm a bit confused because the error in the logs you've send is coming from the oidc_child code while the code part you've highlighted is in the backend. The backend error is just a result of the error in oidc_child, imo.

Can you recompile after running configure with the --enable-sensitive-logs option and run the test again with debug_level = 9 in the [domain/...] section of sssd.conf? This should produce detailed logs with all the http data. Since the logs now might contain sensitive data like the client secret, fell free to send the logs to me directly.

bye,
Sumit

@Maddosaurus

Maddosaurus commented Apr 27, 2026

Copy link
Copy Markdown
Author

Hi,

I'm a bit confused because the error in the logs you've send is coming from the oidc_child code while the code part you've highlighted is in the backend. The backend error is just a result of the error in oidc_child, imo.

I see, thanks for the clarification. I'm not entirely sure where to escape the device code best after the recent changes. Any advice is appreciated.

Can you recompile after running configure with the --enable-sensitive-logs option and run the test again with debug_level = 9 in the [domain/...] section of sssd.conf? This should produce detailed logs with all the http data. Since the logs now might contain sensitive data like the client secret, fell free to send the logs to me directly.

bye, Sumit

You should find the logs in your inbox momentarily.
Thank you for taking a look.
Let me know if there's anything else you need.

@Maddosaurus

Copy link
Copy Markdown
Author

@sumit-bose / @alexey-tikhonov From my point of view the PR is ready for a review. I can confirm that Authentik OIDC now works correctly.

@alexey-tikhonov

Copy link
Copy Markdown
Member

@sumit-bose / @alexey-tikhonov From my point of view the PR is ready for a review. I can confirm that Authentik OIDC now works correctly.

Thank you.

Take a note it will take some time though, as we are going thru release cycle now.

Comment thread src/providers/idp/idp_auth_eval.c Fixed
@alexey-tikhonov

Copy link
Copy Markdown
Member

Hi @Maddosaurus,

sorry for making you wait so long.

I did a first review round, going thru feedback provided by sssd-bot, and added as inline comments items that I find valid / need addressing.

uuid = json_object_get(group, "id");
if (!json_is_string(uuid)) {
uuid = json_object_get(group, "pk");
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will go out of control very soon.
If SSSD is going to support very different IdP providers with different attribute names then there should be name maps (as LDAP based providers have).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand your point. Given the time this PR has been open, and the fact that I'm not very familiar with the codebase (yet), I'd be glad if we could not implement the name map in the context of this PR.
Let's address this in a follow up PR, either by me or a maintainer. How about that?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. Maybe we could have a dedicated feature branch.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can do that. I want to get this current PR wrapped up soon, as it has been open for 2 months now.
I'd really like to land the current changes in SSSD and address improvements either in a feature branch or a follow up PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

there should be no changes to the general backend code. Please see my comments about setting id in authentik_lookup().

bye,
Sumit

char buffer[64];
json_int_t i_val = json_integer_value(tmp);
snprintf(buffer, sizeof(buffer), "%" JSON_INTEGER_FORMAT, i_val);
str = talloc_strdup(mem_ctx, buffer);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use single talloc_asprintf() instead.
But so far I don't understand why this fallback is needed at all.


switch (oidc_cmd) {
case GET_USER_GROUPS:
uri = talloc_asprintf(rest_ctx,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need either to use tmp context and free it at function exit, or free 'uri' explicitly here before assigning new memory allocation.
Otherwise it will hang on 'rest_ctx'.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this only for the Authentik for now - in d75f932

Comment thread src/oidc_child/oidc_child_json.c
@alexey-tikhonov

Copy link
Copy Markdown
Member

@Maddosaurus, please git rebase, not merge.

@Maddosaurus

Copy link
Copy Markdown
Author

@alexey-tikhonov @sumit-bose given this PR has been open for over 2 months now, I would really like to focus on landing these changes in SSSD.
What of the open points is crucial to address in this PR?
Let's focus on clearing these, so we can merge the PR, and address improvements in a feature branch or follow up PR.

Please let me know what we need to address right away. Thanks!

@alexey-tikhonov

Copy link
Copy Markdown
Member

@alexey-tikhonov @sumit-bose given this PR has been open for over 2 months now, I would really like to focus on landing these changes in SSSD. What of the open points is crucial to address in this PR? Let's focus on clearing these, so we can merge the PR, and address improvements in a feature branch or follow up PR.

Please let me know what we need to address right away. Thanks!

It's currently pending @sumit-bose's review.

But to set proper expectations: we are being "swamped" with PRs and requests to support new IdP types - authentik (this PR), Entra ID via himmelblau, Ahdapa IdP, Okta...

This creates a number of issues.
As every IdP type is a little bit different wrt objects lookup, code rapidly evolves into something unsupportable.
Moreover, once we merged something into upstream mainline, we are kind of committed to support / bugfix this, and this doesn't scale.
For those reasons we are considering to hold addition of all new IdP types before we find a solution to make this manageable.
One of the approaches being considered is to implement plugin support (either at 'id_provider' level or sub 'id_provider=idp' level) to allow clear logic separation and also community supported plugins (some of those might be hosted out of SSSD source tree and also downstream distributions would be free to select what support they want to package).

@sumit-bose sumit-bose left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

thank you for your patience. I was finally able to install the authentik containers (it looks like the real docker tools are needed here, I run into issues with the podman based ones coming with Fedora) and test your PR. It is working as expected, but see my comments in the code.

As mentioned otherwise we are thinking about a proper plugin interface e.g. to allow IdPs or other interested parties to provided their own plugins. For the time being I think it makes sense to include your code in the main SSSD tree. But after a first version of the plugin interface is available we might want to remove it from the main tree and host it in a dedicated repository.

bye,
Sumit

: "\", \"verification_uri_complete\": \"",
dc_ctx->verification_uri_complete == NULL ? ""
: dc_ctx->verification_uri_complete);
tmp_json = json_pack("{s:s, s:i, s:i}",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

thank you for adding proper JSON support here. I would suggest to move the generation of the two output line to oidc_child_json.c so that here only a single fprintf() has to be called.

bye,
Sumit

Comment thread src/oidc_child/oidc_child_id.c
* https://api.goauthentik.io/ */
errno_t authentik_lookup(TALLOC_CTX *mem_ctx, enum oidc_cmd oidc_cmd,
char *base_url,
char *input, enum search_str_type input_type,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

yes, basically input_type is a placeholder for lookups by id which might be available in future. If you want to avoid this warning you can add something like e.g.

    if (input_type ==TYPE_OBJECT_ID) {
        ret = ENOTSUP;
        goto done;
    }

bye,
Sumit

rest_ctx, get_http_data(rest_ctx), "results", "pk");

if (obj_id == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to read mandatory object id.\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

please read uid for users and pk for groups here and store the values as id in out. This way you cam remove the changes in idp_id_eval.c. It is expected that out contains besides posixUsername etc which are added inadd_posix_to_json() the id attribute which a unique identifier for the user or group object. Since this unique attribute is provider specific it is best to set it here instead of figuring it out in the backend.

Additionally, since you need the user's pk for the group-memberships I would suggest to create a get_str_attr_from_embed_json_int() to avoid the fallback in get_json_string().

bye,
Sumit

json_t *id_object = NULL;
const char *user_identifier = NULL;
const char *id_attr_list[] = { "sub", "id", NULL };
const char *id_attr_list[4];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

what is the purpose of this change? I'm asking because it is changing the behavior of this function. If user_identifier_attr is given the function should only be successful if user_identifier_attr is present, there should be no fall back. Only if user_identifier_attr is not set sub and id should be checked.

bye,
Sumit

uuid = json_object_get(group, "id");
if (!json_is_string(uuid)) {
uuid = json_object_get(group, "pk");
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

there should be no changes to the general backend code. Please see my comments about setting id in authentik_lookup().

bye,
Sumit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Changes requested no-backport This should go to target branch only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for Authentik OIDC

5 participants