Skip to content

Specify audience for oauth resource server protection #14545

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
coryschwartz opened this issue May 18, 2025 · 1 comment
Open

Specify audience for oauth resource server protection #14545

coryschwartz opened this issue May 18, 2025 · 1 comment
Labels
enhancement New feature or request

Comments

@coryschwartz
Copy link

Using authentik is difficult to protect resources in the way defined in oauth standards (RFC 6749, etc)

I'm trying to use authentik to authenticate a typical Oauth configuration, one with multiple resource server hosting resources and multiple client applications (CLI, web, javascript-spa, 3rd party) where users can grant limited access to their resources to their third party applications.

I'm struggling to do this well using Authentik. While it supports the Oauth+OIDC use case perfectly well. (and quite easily, I might add!) I notice that access tokens issued by Authentik have the aud set to the client_id of the client, and I don't know of any way to have tokens issued by authentik where the audience is a separate resource server. I think with a small change authentik for oauth 3rd party delegation use case.

For an example from another auth server solution, auth0 allows users to register their own APIs. The feature I'm talking about would be similar to that.

Describe the solution you'd like

Ideally, there would be a distinction between client and resource server. Clients would request the resource they wanted an access token for, and authentik would issue a token to client AAAA where resource server XXXX is the audience.

For an example of what I'm talking about see RFC9068 Section 3.

This demonstrates the client doing oauth auth code step. It authenticates with the auth server using it's own client_id and requests a specific resource server during exchange. The auth server responds with an access token where the audience is set to the resource.

   Example request below:

   GET /as/authorization.oauth2?response_type=code
           &client_id=s6BhdRkqt3
           &state=xyz
           &scope=openid%20profile%20reademail
           &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
           &resource=https%3A%2F%2Frs.example.com%2F HTTP/1.1
        Host: authorization-server.example.com

     Figure 1: Authorization Request with Resource and Scope Parameters

   Once redeemed, the code obtained from the request above will result
   in a JWT access token in the form shown below:

   Header:

      {"typ":"at+JWT","alg":"RS256","kid":"RjEwOwOA"}

   Claims:

      {
        "iss": "https://authorization-server.example.com/",
        "sub": "5ba552d67",
        "aud":   "https://rs.example.com/",
        "exp": 1639528912,
        "iat": 1618354090,
        "jti" : "dbe39bf3a3ba4238a513f51d6e1691c4",
        "client_id": "s6BhdRkqt3",
        "scope": "openid profile reademail"
      }

       Figure 2: The Header and JWT Claims Set of a JWT Access Token

to make this work in authentik, I think it would be handled similarly to the way scopes are now. If requested, and if some policy mapping allows it, then it's included on the token.

Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.

For a concrete example, let's say we have resource servers are "file server" and "photo server" where we want to gate access to these resource servers using authentik group memberships. Lets say that they are accessed by CLI or web clients.

Thee are some workarounds. None of these are right:

  1. Register a public oauth client in authentik, and distribute the same client ID to all clients. Web clients, CLI clients, they all get the public client ID. Configure resource servers to accept tokens where this client_id is the audience, and use scopes to determine whether the access was actually granted to a particular service. This clearly reduces the security, and it is not a recommended practice. For one thing, if it turns out that a particular implementation is misbehaving, we have no way of revoking that client.

You would have to setup some rules in authentik to the affect of if the user is in group "photos" then grant scopes to determine actual access

CLI Client Web Client Photo Server File Server
AAAA AAAA AAAA AAAA

and the token would be like this:

{sub: me, aud: AAAA, scopes: "photos:yes,files:no" }

  1. Each client implementation gets its own client_id, and resource servers are configured to accept tokens from any of the various audiences. This is not an ideal solution since we cannot add new clients without also re-configuring resource servers, however this does have the benefit of being able to revoke individual clients.

Similarly to the first option, you'd need to allow access tokens to be granted to everyone, and use scopes to actually gate access to resources.

CLI Client Web Client Photo Server File Server
AAAA BBBB AAAA or BBBB AAAA or BBBB
  1. The inverse of 2, 3rd party clients will register multiple client IDS, one for each resource server they need to use.

This workaround has the benefit that users can be denied an access_token based on group membership and will not be able to present a valid bearer token if their access is actually denied, however, it inherits the problem from 1 where clients cannot be individually revoked.

CLI Client Web Client Photo Server File Server
XXXX & YYYY XXXX & YYYY XXXX YYYY

Additional context
Add any other context or screenshots about the feature request here.

@coryschwartz coryschwartz added the enhancement New feature or request label May 18, 2025
@coryschwartz
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant