goauthentik / goauthentik/authentik

Specify audience for oauth resource server protection

Open
#14,545 1 comment 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
25.6k
Forks
2k
Avg merge
1d 1h
Merged PRs (30d)
644

Description

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" }

2. 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

3. 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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.