WaitForDeviceToken polls the tenant to get access/refresh tokens for the user. This should be called after GetDeviceCode, and will block until the user has authenticated or we have reached the time limit for authenticating (based on the response from GetDeviceCode).
(ctx context.Context, state State)
| 96 | // authenticated or we have reached the time limit for authenticating (based on |
| 97 | // the response from GetDeviceCode). |
| 98 | func (a API) WaitForDeviceToken(ctx context.Context, state State) (TokenResponse, error) { |
| 99 | // Ticker for polling tenant for login – based on the interval |
| 100 | // specified by the tenant response. |
| 101 | ticker := time.NewTimer(state.IntervalDuration()) |
| 102 | defer ticker.Stop() |
| 103 | // The tenant tells us for as long as we can poll it for credentials |
| 104 | // while the user logs in through their browser. Timeout if we don't get |
| 105 | // credentials within this period. |
| 106 | timeout := time.NewTimer(state.ExpiryDuration()) |
| 107 | defer timeout.Stop() |
| 108 | |
| 109 | for { |
| 110 | resetTimer(ticker, state.IntervalDuration()) |
| 111 | select { |
| 112 | case <-ctx.Done(): |
| 113 | // user canceled login |
| 114 | return TokenResponse{}, ctx.Err() |
| 115 | case <-ticker.C: |
| 116 | // tick, check for user login |
| 117 | res, err := a.getDeviceToken(ctx, state) |
| 118 | if err != nil { |
| 119 | if errors.Is(err, context.Canceled) { |
| 120 | // if the caller canceled the context, continue |
| 121 | // and let the select hit the ctx.Done() branch |
| 122 | continue |
| 123 | } |
| 124 | return TokenResponse{}, err |
| 125 | } |
| 126 | |
| 127 | if res.Error != nil { |
| 128 | if *res.Error == "authorization_pending" { |
| 129 | continue |
| 130 | } |
| 131 | |
| 132 | return res, errors.New(res.ErrorDescription) |
| 133 | } |
| 134 | |
| 135 | return res, nil |
| 136 | case <-timeout.C: |
| 137 | // login timed out |
| 138 | return TokenResponse{}, ErrTimeout |
| 139 | } |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | // resetTimer is a helper function thatstops, drains and resets the timer. |
| 144 | // This is necessary in go versions <1.23, since the timer isn't stopped + |