spring-security icon indicating copy to clipboard operation
spring-security copied to clipboard

Add support for OAuth 2.0 Device Authorization Grant

Open yogeshVU opened this issue 3 years ago • 14 comments

We should consider adding support for OAuth 2.0 Device Authorization Grant.

Related gh-12852

yogeshVU avatar Apr 05 '22 19:04 yogeshVU

Hi! I would like to work on this one this summer if is possible

sgiannino avatar Jun 27 '22 07:06 sgiannino

I have added DeviceCodeOAuth2AuthorizedClientProvider. The OAuth2AuthorizationContext should be based on the response from the device authorization endpoint. I haven't added it to OAuth2AuthorizedClientProviderBuilder and DefaultOAuth2AuthorizedClientManager yet. I'm not sure yet how suitable this solution is.

franticticktick avatar Mar 28 '24 15:03 franticticktick

@CrazyParanoid thanks for wanting to work on this! Please note that it's best to discuss an issue and have it assigned first before working on it. Have you seen the sample code in Spring Authorization Server for this?

I have discussed this issue with @jgrandja in the past and while we haven't ruled out providing support in Spring Security for this (this issue), there is not any evidence that Spring Security requires client-side support. The reason for this is that it seems likely many device grant clients will be public clients implemented in native apps (e.g. tvOS, Android TV, etc.) and not written in Java or running on Spring powered backends. Do you have a use case for a device grant client that uses Spring Security? If so, can you please share some information about it?

sjohnr avatar Mar 28 '24 20:03 sjohnr

Hi @sjohnr, thanks for you feedback! I can describe the implementation of device code flow on BFF, which I am implementing in my project. To implement such an architecture, I need a bff gateway, for example, spring cloud gateway. To start authentication, I implemented the request:

    @PostMapping("/auth")
    public void authenticate(@RequestBody AuthRequest request) {
        OAuth2DeviceAuthorizationResponse response = oAuth2VerificationProvider.verify(OAuth2VerificationRequest.from(clientRegistration));
        smsService.sendSms(new SmsRequest(request.getPhone(), response.getVerificationUriComplete()));
    }

I have my custom OAuth2VerificationProvider component:

public interface OAuth2VerificationProvider {

    OAuth2DeviceAuthorizationResponse verify(OAuth2VerificationRequest request);

}

With implementation:

public class DeviceCodeOAuth2VerificationProvider implements OAuth2VerificationProvider {

    private final OAuth2VerificationWebClient<OAuth2VerificationRequest> deviceCodeOAuth2VerificationWebClient = new DeviceCodeOAuth2VerificationWebClient();
    private final PollingOAuth2AuthorizedClientManager auth2AuthorizedClientManager = new PollingOAuth2AuthorizedClientManager();

    @Override
    public OAuth2DeviceAuthorizationResponse verify(OAuth2VerificationRequest request) {
        OAuth2DeviceAuthorizationResponse authorizationResponse = deviceCodeOAuth2VerificationWebClient.getOAuth2VerificationResponse(request);
        auth2AuthorizedClientManager.setPollingAuthenticationTask(
                new AuthenticationTask(authorizationResponse.getDeviceCode(),
                        authorizationResponse.getInterval())
        );

        return authorizationResponse;
    }
}

This component first receives a response from the IDP, after which the IDP polling process will be started to obtain the token. PollingOAuth2AuthorizedClientManager delegates a request to DefaultOAuth2AuthorizedClientManager on a schedule with settings received from deviceCodeOAuth2VerificationWebClient. DefaultOAuth2AuthorizedClientManager must support DeviceCodeOAuth2AuthorizedClientProvider. I send SMS to user with verificationUriComplete. After receiving authentication, routes with TokenRelay start working.

franticticktick avatar Mar 29 '24 12:03 franticticktick

Hi @CrazyParanoid, thanks for providing those details.

Generally, device code provides an OAuth2 flow for devices that are input constrained, meaning there's no keyboard or it is not convenient to present one to the user for traditional authentication and consent for authorization. Based on the code you have provided, it seems possible you are implementing an out-of-band authentication mechanism (similar to an MFA second factor) on top of device code, which is not exactly what device code is intended for. Also, I feel that providing a phone number as a means for initiating the authorization flow on another device is not in keeping with the intent of the device grant specification, which states:

5.7. Non-Visual Code Transmission

There is no requirement that the user code be displayed by the device visually. Other methods of one-way communication can potentially be used, such as text-to-speech audio or Bluetooth Low Energy. To mitigate an attack in which a malicious user can bootstrap their credentials on a device not in their control, it is RECOMMENDED that any chosen communication channel only be accessible by people in close proximity, for example, users who can see or hear the device.

Can you describe why you are not using the authorization code grant for your use case? Am I correct that you're trying to design an out-of-band authentication flow? Or are requests to this BFF actually coming from an input-constrained device?

sjohnr avatar Mar 29 '24 15:03 sjohnr

In my case, I have an embedded system with an operating system with very limited functionality. There are quite a lot of such embedded systems and there is no way to implement traditional browser flow, for example, authorization code grant. As you correctly noted:

There is no requirement that the user code be displayed by the device visually.

From which I conclude that sending verification_uri_complete does not contradict the specification, but it is quite possible that I am very mistaken.

Also, I feel that providing a phone number as a means for initiating the authorization flow on another device is not in keeping with the intent of the device grant specification

Most likely you are right, the goal of my architecture was to achieve the implementation of device code flow through BFF, which carries certain benefits. This has led to some compromises, but that's just my opinion. I didn't know that device code grant support is not planned in spring security, sorry for the premature PR.

franticticktick avatar Mar 29 '24 20:03 franticticktick

Thanks for the additional details, @CrazyParanoid. I think it's important for cases like this to identify one or two solid use cases to understand how this support might be used before committing to including it (if there's a question about whether it should be included, which there is in this case).

I didn't know that device code grant support is not planned in spring security, sorry for the premature PR.

Please don't worry about that, I am glad you are interested in providing it. Having the conversation first is helpful though. It's not that support isn't planned, only that we are unsure whether it will be useful and worth providing. I'll discuss this with @jgrandja in the next week or so and get back to you on whether your use case provides a good incentive for including it.

sjohnr avatar Apr 01 '24 14:04 sjohnr

@CrazyParanoid as you may know, we generally prioritize features based on community upvotes on issues. Currently, this issue only has one upvote (👍) after being opened over a year, which seems to suggest there is very low demand for this support in Spring Security. After discussing this internally, we feel like it would be worth waiting to provide client support for OAuth 2.0 Device Authorization Grant once there is more community demand for the feature, so we will not proceed to the PR stage at this time. If anyone in the community has need for this support in Spring Security, I'd encourage them to upvote this issue so that we can prioritize it.

In the meantime, you are of course welcome to re-use the classes from implementation you provided in the PR (gh-14816) or the classes from the demo client in Spring Authorization Server samples.

sjohnr avatar Apr 04 '24 18:04 sjohnr

What's the most recent advice on this? We might have a need for device flow support. Kind Thanks

colin-riddell avatar Jul 04 '24 13:07 colin-riddell

No updates at this time, @colin-riddell.

If you get to the point where you have a clearly defined need for the device flow in your client, it would be extremely helpful if you could provide some high level details (as mentioned above) of your use case. For example, what client/server arrangement do you have such that you would be able to make use of a device code client in a Spring application (as opposed to a native app client, for example).

sjohnr avatar Jul 05 '24 16:07 sjohnr

Hi @sjohnr - This wouldn't be to support a Spring Application based client at all. It's a bare-bones reduced capacity thin client that runs as part of a lightweight application for media/STB. It's got reduced capacity for interaction and computation. Not quite embedded but close. I understand that that there'd be absolutely no need to support this flow for a client that can run a Spring application.

Maybe I misunderstand; but there's presumably no valid use-case for this kind of flow for a Spring application client?

colin-riddell avatar Jul 05 '24 16:07 colin-riddell

Hey @colin-riddell.

This wouldn't be to support a Spring Application based client at all.

Ok. So it sounds like you would only have use for the Spring Authorization Server support (which is already available since the 1.2 release).

Maybe I misunderstand; but there's presumably no valid use-case for this kind of flow for a Spring application client?

I think there probably are valid use cases, it's just that I don't have a clear idea of what those use cases are so we need folks in the community to outline one or more of them for us so we can decide if it's truly useful to add support to the framework. Certainly, I think there are fewer good use cases for device code grant in a Spring application client than for other grant types (such as the ones already supported).

sjohnr avatar Jul 05 '24 22:07 sjohnr

Hey @sjohnr

Ah ok I didn't realise that Authorization Server supported it already. It wasn't clear to me. I apologize. Kind thanks

colin-riddell avatar Jul 05 '24 22:07 colin-riddell

I've had an interesting use-case for device-code grant: CLI apps that do not wish to (or cannot) open an ephemeral port.

When I build a Spring Shell app, and I want to avoid running a full web-server inside that app, it is much easier to go through the device_code grant rather than try and fine-tune the app to open a small web server and close it after a token has been obtained.

It is also useful in scenarios where loopback redirects are painful, e.g. when working over SSH where tunneling on ephemeral is extremely unwieldy.

Kehrlann avatar Apr 28 '25 13:04 Kehrlann

I've had an interesting use-case for device-code grant: CLI apps that do not wish to (or cannot) open an ephemeral port.

When I build a Spring Shell app, and I want to avoid running a full web-server inside that app, it is much easier to go through the device_code grant rather than try and fine-tune the app to open a small web server and close it after a token has been obtained.

It is also useful in scenarios where loopback redirects are painful, e.g. when working over SSH where tunneling on ephemeral is extremely unwieldy.

In my company we have some applications that run in user machines, some RPA's written in python, they need to login with user credentials to act in behalf of the user, after that there is no user interaction, as an effort towards modernization and more security we are migrating some apps to spring. After reading the docs, i stumbled upon spring shell wich seams a great replacement for the RPA's mentioned, so i think that would be great that the apps could have a command to login, something similar to oc login, but the jwt token is too large to force user to copy it over shell and we dont want to extend the duration of the tokens only for this cases, so wold be nice if we could use device grant to receive a token/refresh to manage it during the execution of such applications.

renandiaraujocruz avatar Sep 12 '25 00:09 renandiaraujocruz

Leaving this here for those who would like to bootstrap non-web-based Device Code grant: sample code. Please note that it is a PoC implementation, and, as such, it is extremely rough. Do not use in prod as-is.

Kehrlann avatar Sep 22 '25 10:09 Kehrlann