Skip to content
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

Implicit auth cannot be natively used by confidential clients #115

Closed
night opened this issue Mar 13, 2019 · 9 comments
Closed

Implicit auth cannot be natively used by confidential clients #115

night opened this issue Mar 13, 2019 · 9 comments

Comments

@night
Copy link

night commented Mar 13, 2019

An important distinction for confidential clients versus public clients is that confidential clients can also be used as public clients (as long as the authorization server supports it). Over at

and client.check_client_type('public'):
a check is performed to assert that a client is public, which fails for confidential clients when implicit auth is invoked. While a custom authentication scheme can be created for this specific case, there is other logic in this library which depends on clients having a fixed type too, like PKCE. check_client_type should probably be removed from such flows, instead relying on the request alone to dictate the authentication schemes supported for the flow (already true to an extent with TOKEN_ENDPOINT_AUTH_METHODS).

A client may be implemented as a distributed set of components, each
with a different client type and security context (e.g., a
distributed client with both a confidential server-based component
and a public browser-based component). If the authorization server
does not provide support for such clients or does not provide
guidance with regard to their registration, the client SHOULD
register each component as a separate client.

More info at https://tools.ietf.org/html/rfc6749#section-2.1

@lepture
Copy link
Owner

lepture commented Mar 18, 2019

A client may be implemented as a distributed set of components, each
with a different client type and security context

**each with a different client type and security context **. You can design the client as:

class App:
    app_id = column()

class Client:
    app_id = reference(App)
    ...

In this case, the App is the mixed "client", and the Client is the components.

@lepture lepture closed this as completed Mar 18, 2019
@night
Copy link
Author

night commented Mar 18, 2019

Thanks for the response. That's better than what I had (fixes the other downstream logic depending on client type), but unfortunately I still need to overwrite the authentication handlers to overwrite the query_client to selectively choose a public or confidential client class. Any chance you could extend query_client to pass in auth_method as an arg? It would allow query_client to selectively choose a client type based on the request being made.

@lepture
Copy link
Owner

lepture commented Mar 19, 2019

@night each with a different client type and security context In this case, the client_id and client_secret will be different.

@night
Copy link
Author

night commented Mar 19, 2019

Unfortunately that's not something that is possible in my upgrade path. In the system I work on every application has one client/secret pair. This is the case on almost every OAuth2 provider I can think of, even Google/Facebook operate this way. I think you have the only library which actually has strict client type handling like this. I suspect if this library gets any traction you will run into others in my predicament as well for this reason.

@night
Copy link
Author

night commented Mar 19, 2019

for more context, here's an approach I have to solve this locally:

class PublicClient(Application):
    def check_client_type(self, client_type):
        return 'public' == client_type


class ConfidentialClient(Application):
    def check_client_type(self, client_type):
        return self.confidential and 'confidential' == client_type


def authenticate_client(query_client, func):
    def authenticate(_query_client, request):
        return func(query_client, request)

    return authenticate

oauth2_server.register_client_auth_method(
    'none', authenticate_client(PublicClient.query_one, authenticate_none)
)
oauth2_server.register_client_auth_method(
    'client_secret_basic', authenticate_client(ConfidentialClient.query_one, authenticate_client_secret_basic),
)
oauth2_server.register_client_auth_method(
    'client_secret_post', authenticate_client(ConfidentialClient.query_one, authenticate_client_secret_post),
)

My intent is to have the client authentication scheme dictate the client type, which allows this library to work properly in the mindset that all clients can be public clients, but public clients cannot be confidential clients.

It's worth noting that the RFC does mention this use case in one line of the RFC in a section with redirect URLs, implying this is supported behavior:

The authorization server MUST require the following clients to
register their redirection endpoint:

o Public clients.

o Confidential clients utilizing the implicit grant type.

The authorization server SHOULD require all clients to register their
redirection endpoint prior to utilizing the authorization endpoint.

@lepture
Copy link
Owner

lepture commented Mar 19, 2019

@night I think I finally got what you want:

class OAuthClient(Client):
    def check_client_type(self, client_type):
        if self.client_type == 'confidential':
            # confidential client can also support public client type
            return True
        return self.client_type == client_type

You can overwrite this check_client_type to get what you want.

@night
Copy link
Author

night commented Mar 19, 2019

@lepture That's actually the first solution I had, but the problem with that is it fixes implicit auth for a confidential client acting as a public client, but it breaks the refresh token grant for confidential clients because of

if client.check_client_type('public'):

@lepture
Copy link
Owner

lepture commented Mar 19, 2019

@night you are right. I changed the if condition in refresh token.

@night
Copy link
Author

night commented Mar 19, 2019

I think this will work. Will followup if there's anything else. Thanks for the quick fixes to all these issues btw. Library is much improved vs. flask-oauthlib

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

No branches or pull requests

2 participants