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

Show a message if refresh token is expired and device authentication is required #774

Open
adombeck opened this issue Feb 3, 2025 · 3 comments
Labels

Comments

@adombeck
Copy link
Contributor

adombeck commented Feb 3, 2025

ubuntu/authd-oidc-brokers#325 will fix #575, i.e. it will automatically prompt the user to perform device authentication, after they entered the local password, if the refresh token has expired. That behavior is surprising though, the user is not informed why they are asked to perform device authentication. So we should display a message, either before the device authentication prompt or in the prompt itself.

UDENG-5917

@adombeck
Copy link
Contributor Author

adombeck commented Feb 3, 2025

This needs to be implemented in the PAM module. Do you want to take it, @3v1n0?

@3v1n0
Copy link
Collaborator

3v1n0 commented Feb 3, 2025

This needs to be implemented in the PAM module. Do you want to take it, @3v1n0?

So it should be broker responsability to send a message after authentication is done, no?

Thus, after the local password authentication succeeded it should attach a message... And the UI side should show it.

@adombeck
Copy link
Contributor Author

adombeck commented Feb 4, 2025

So it should be broker responsability to send a message after authentication is done, no?

Thus, after the local password authentication succeeded it should attach a message... And the UI side should show it.

Yes, that's how it should work, but the message is not visible. Here is what I did to test it:

  1. Apply this patch to the broker, to make it return the error message we want to show:
diff --git a/internal/broker/broker.go b/internal/broker/broker.go
index 93d0d82..353c74d 100644
--- a/internal/broker/broker.go
+++ b/internal/broker/broker.go
@@ -628,7 +628,7 @@ func (b *Broker) handleIsAuthenticated(ctx context.Context, session *session, au
                        if errors.As(err, &retrieveErr) && b.provider.IsTokenExpiredError(*retrieveErr) {
                                // The refresh token is expired, so the user needs to authenticate via OIDC again.
                                session.nextAuthModes = []string{authmodes.Device, authmodes.DeviceQr}
-                               return AuthNext, nil
+                               return AuthNext, errorMessage{Message: "refresh token expired"}
                        }
                        if err != nil {
                                log.Error(context.Background(), err.Error())
@@ -810,6 +810,9 @@ func (b *Broker) updateSession(sessionID string, session session) error {
 func (b *Broker) refreshToken(ctx context.Context, oauth2Config oauth2.Config, oldToken token.AuthCachedInfo) (token.AuthCachedInfo, error) {
        timeoutCtx, cancel := context.WithTimeout(ctx, maxRequestDuration)
        defer cancel()
+
+       return token.AuthCachedInfo{}, &oauth2.RetrieveError{ErrorCode: "invalid_grant", ErrorDescription: "AADSTS50173: Refresh token is expired"}
+
        // set cached token expiry time to one hour in the past
        // this makes sure the token is refreshed even if it has not 'actually' expired
        oldToken.Token.Expiry = time.Now().Add(-time.Hour)
  1. Apply this patch to authd, to make it support error messages returned with auth.Next:
diff --git a/internal/brokers/broker.go b/internal/brokers/broker.go
index 7f8801f4..78519a85 100644
--- a/internal/brokers/broker.go
+++ b/internal/brokers/broker.go
@@ -194,8 +194,13 @@ func (b Broker) IsAuthenticated(ctx context.Context, sessionID, authenticationDa
                if _, err := unmarshalAndGetKey(data, "message"); err != nil {
                        return "", "", err
                }
-
-       case auth.Cancelled, auth.Next:
+       case auth.Next:
+               if data != "{}" {
+                       if _, err := unmarshalAndGetKey(data, "message"); err != nil {
+                               return "", "", err
+                       }
+               }
+       case auth.Cancelled:
                if data != "{}" {
                        return "", "", fmt.Errorf("access mode %q should not return any data, got: %v", access, data)
                }

Afterwards I try to log in via authd, either via sudo login or GDM, but I don't see the error message.

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

No branches or pull requests

2 participants