Rename Machine to Node (#1553)

This commit is contained in:
Juan Font 2023-09-24 13:42:05 +02:00 committed by GitHub
parent 096ac31bb3
commit 0030af3fa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 5222 additions and 5238 deletions

View file

@ -27,9 +27,9 @@ func (h *Headscale) handleRegister(
isNoise bool,
) {
now := time.Now().UTC()
machine, err := h.db.GetMachineByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
node, err := h.db.GetNodeByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
if errors.Is(err, gorm.ErrRecordNotFound) {
// If the machine has AuthKey set, handle registration via PreAuthKeys
// If the node has AuthKey set, handle registration via PreAuthKeys
if registerRequest.Auth.AuthKey != "" {
h.handleAuthKey(writer, registerRequest, machineKey, isNoise)
@ -40,7 +40,7 @@ func (h *Headscale) handleRegister(
//
// TODO(juan): We could use this field to improve our protocol implementation,
// and hold the request until the client closes it, or the interactive
// login is completed (i.e., the user registers the machine).
// login is completed (i.e., the user registers the node).
// This is not implemented yet, as it is no strictly required. The only side-effect
// is that the client will hammer headscale with requests until it gets a
// successful RegisterResponse.
@ -48,19 +48,19 @@ func (h *Headscale) handleRegister(
if _, ok := h.registrationCache.Get(util.NodePublicKeyStripPrefix(registerRequest.NodeKey)); ok {
log.Debug().
Caller().
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Str("machine_key", machineKey.ShortString()).
Str("node_key", registerRequest.NodeKey.ShortString()).
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
Str("follow_up", registerRequest.Followup).
Bool("noise", isNoise).
Msg("Machine is waiting for interactive login")
Msg("Node is waiting for interactive login")
select {
case <-req.Context().Done():
return
case <-time.After(registrationHoldoff):
h.handleNewMachine(writer, registerRequest, machineKey, isNoise)
h.handleNewNode(writer, registerRequest, machineKey, isNoise)
return
}
@ -69,13 +69,13 @@ func (h *Headscale) handleRegister(
log.Info().
Caller().
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Str("machine_key", machineKey.ShortString()).
Str("node_key", registerRequest.NodeKey.ShortString()).
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
Str("follow_up", registerRequest.Followup).
Bool("noise", isNoise).
Msg("New machine not yet in the database")
Msg("New node not yet in the database")
givenName, err := h.db.GenerateGivenName(
machineKey.String(),
@ -92,11 +92,11 @@ func (h *Headscale) handleRegister(
return
}
// The machine did not have a key to authenticate, which means
// The node did not have a key to authenticate, which means
// that we rely on a method that calls back some how (OpenID or CLI)
// We create the machine and then keep it around until a callback
// We create the node and then keep it around until a callback
// happens
newMachine := types.Machine{
newNode := types.Node{
MachineKey: util.MachinePublicKeyStripPrefix(machineKey),
Hostname: registerRequest.Hostinfo.Hostname,
GivenName: givenName,
@ -109,41 +109,41 @@ func (h *Headscale) handleRegister(
log.Trace().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Time("expiry", registerRequest.Expiry).
Msg("Non-zero expiry time requested")
newMachine.Expiry = &registerRequest.Expiry
newNode.Expiry = &registerRequest.Expiry
}
h.registrationCache.Set(
newMachine.NodeKey,
newMachine,
newNode.NodeKey,
newNode,
registerCacheExpiration,
)
h.handleNewMachine(writer, registerRequest, machineKey, isNoise)
h.handleNewNode(writer, registerRequest, machineKey, isNoise)
return
}
// The machine is already in the DB. This could mean one of the following:
// - The machine is authenticated and ready to /map
// The node is already in the DB. This could mean one of the following:
// - The node is authenticated and ready to /map
// - We are doing a key refresh
// - The machine is logged out (or expired) and pending to be authorized. TODO(juan): We need to keep alive the connection here
if machine != nil {
// - The node is logged out (or expired) and pending to be authorized. TODO(juan): We need to keep alive the connection here
if node != nil {
// (juan): For a while we had a bug where we were not storing the MachineKey for the nodes using the TS2021,
// due to a misunderstanding of the protocol https://github.com/juanfont/headscale/issues/1054
// So if we have a not valid MachineKey (but we were able to fetch the machine with the NodeKeys), we update it.
// So if we have a not valid MachineKey (but we were able to fetch the node with the NodeKeys), we update it.
var storedMachineKey key.MachinePublic
err = storedMachineKey.UnmarshalText(
[]byte(util.MachinePublicKeyEnsurePrefix(machine.MachineKey)),
[]byte(util.MachinePublicKeyEnsurePrefix(node.MachineKey)),
)
if err != nil || storedMachineKey.IsZero() {
if err := h.db.MachineSetMachineKey(machine, machineKey); err != nil {
if err := h.db.NodeSetMachineKey(node, machineKey); err != nil {
log.Error().
Caller().
Str("func", "RegistrationHandler").
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Err(err).
Msg("Error saving machine key to database")
@ -154,34 +154,34 @@ func (h *Headscale) handleRegister(
// If the NodeKey stored in headscale is the same as the key presented in a registration
// request, then we have a node that is either:
// - Trying to log out (sending a expiry in the past)
// - A valid, registered machine, looking for /map
// - Expired machine wanting to reauthenticate
if machine.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.NodeKey) {
// - A valid, registered node, looking for /map
// - Expired node wanting to reauthenticate
if node.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.NodeKey) {
// The client sends an Expiry in the past if the client is requesting to expire the key (aka logout)
// https://github.com/tailscale/tailscale/blob/main/tailcfg/tailcfg.go#L648
if !registerRequest.Expiry.IsZero() &&
registerRequest.Expiry.UTC().Before(now) {
h.handleMachineLogOut(writer, *machine, machineKey, isNoise)
h.handleNodeLogOut(writer, *node, machineKey, isNoise)
return
}
// If machine is not expired, and it is register, we have a already accepted this machine,
// If node is not expired, and it is register, we have a already accepted this node,
// let it proceed with a valid registration
if !machine.IsExpired() {
h.handleMachineWithValidRegistration(writer, *machine, machineKey, isNoise)
if !node.IsExpired() {
h.handleNodeWithValidRegistration(writer, *node, machineKey, isNoise)
return
}
}
// The NodeKey we have matches OldNodeKey, which means this is a refresh after a key expiration
if machine.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.OldNodeKey) &&
!machine.IsExpired() {
h.handleMachineKeyRefresh(
if node.NodeKey == util.NodePublicKeyStripPrefix(registerRequest.OldNodeKey) &&
!node.IsExpired() {
h.handleNodeKeyRefresh(
writer,
registerRequest,
*machine,
*node,
machineKey,
isNoise,
)
@ -197,20 +197,20 @@ func (h *Headscale) handleRegister(
}
}
// The machine has expired or it is logged out
h.handleMachineExpiredOrLoggedOut(writer, registerRequest, *machine, machineKey, isNoise)
// The node has expired or it is logged out
h.handleNodeExpiredOrLoggedOut(writer, registerRequest, *node, machineKey, isNoise)
// TODO(juan): RegisterRequest includes an Expiry time, that we could optionally use
machine.Expiry = &time.Time{}
node.Expiry = &time.Time{}
// If we are here it means the client needs to be reauthorized,
// we need to make sure the NodeKey matches the one in the request
// TODO(juan): What happens when using fast user switching between two
// headscale-managed tailnets?
machine.NodeKey = util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
node.NodeKey = util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
h.registrationCache.Set(
util.NodePublicKeyStripPrefix(registerRequest.NodeKey),
*machine,
*node,
registerCacheExpiration,
)
@ -231,7 +231,7 @@ func (h *Headscale) handleAuthKey(
) {
log.Debug().
Caller().
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Bool("noise", isNoise).
Msgf("Processing auth key for %s", registerRequest.Hostinfo.Hostname)
resp := tailcfg.RegisterResponse{}
@ -241,7 +241,7 @@ func (h *Headscale) handleAuthKey(
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Err(err).
Msg("Failed authentication via AuthKey")
resp.MachineAuthorized = false
@ -251,11 +251,11 @@ func (h *Headscale) handleAuthKey(
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Err(err).
Msg("Cannot encode message")
http.Error(writer, "Internal server error", http.StatusInternalServerError)
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
return
@ -275,14 +275,14 @@ func (h *Headscale) handleAuthKey(
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Msg("Failed authentication via AuthKey")
if pak != nil {
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
} else {
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", "unknown").Inc()
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", "unknown").Inc()
}
return
@ -291,33 +291,33 @@ func (h *Headscale) handleAuthKey(
log.Debug().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Msg("Authentication key was valid, proceeding to acquire IP addresses")
nodeKey := util.NodePublicKeyStripPrefix(registerRequest.NodeKey)
// retrieve machine information if it exist
// retrieve node information if it exist
// The error is not important, because if it does not
// exist, then this is a new machine and we will move
// exist, then this is a new node and we will move
// on to registration.
machine, _ := h.db.GetMachineByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
if machine != nil {
node, _ := h.db.GetNodeByAnyKey(machineKey, registerRequest.NodeKey, registerRequest.OldNodeKey)
if node != nil {
log.Trace().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Msg("machine was already registered before, refreshing with new auth key")
Str("node", node.Hostname).
Msg("node was already registered before, refreshing with new auth key")
machine.NodeKey = nodeKey
machine.AuthKeyID = uint(pak.ID)
err := h.db.MachineSetExpiry(machine, registerRequest.Expiry)
node.NodeKey = nodeKey
node.AuthKeyID = uint(pak.ID)
err := h.db.NodeSetExpiry(node, registerRequest.Expiry)
if err != nil {
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Err(err).
Msg("Failed to refresh machine")
Msg("Failed to refresh node")
return
}
@ -325,16 +325,16 @@ func (h *Headscale) handleAuthKey(
aclTags := pak.Proto().AclTags
if len(aclTags) > 0 {
// This conditional preserves the existing behaviour, although SaaS would reset the tags on auth-key login
err = h.db.SetTags(machine, aclTags)
err = h.db.SetTags(node, aclTags)
if err != nil {
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Strs("aclTags", aclTags).
Err(err).
Msg("Failed to set tags after refreshing machine")
Msg("Failed to set tags after refreshing node")
return
}
@ -355,7 +355,7 @@ func (h *Headscale) handleAuthKey(
return
}
machineToRegister := types.Machine{
nodeToRegister := types.Node{
Hostname: registerRequest.Hostinfo.Hostname,
GivenName: givenName,
UserID: pak.User.ID,
@ -368,16 +368,16 @@ func (h *Headscale) handleAuthKey(
ForcedTags: pak.Proto().AclTags,
}
machine, err = h.db.RegisterMachine(
machineToRegister,
node, err = h.db.RegisterNode(
nodeToRegister,
)
if err != nil {
log.Error().
Caller().
Bool("noise", isNoise).
Err(err).
Msg("could not register machine")
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Msg("could not register node")
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -392,7 +392,7 @@ func (h *Headscale) handleAuthKey(
Bool("noise", isNoise).
Err(err).
Msg("Failed to use pre-auth key")
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
@ -410,16 +410,16 @@ func (h *Headscale) handleAuthKey(
log.Error().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "error", pak.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "success", pak.User.Name).
nodeRegistrations.WithLabelValues("new", util.RegisterMethodAuthKey, "success", pak.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
writer.WriteHeader(http.StatusOK)
@ -434,14 +434,14 @@ func (h *Headscale) handleAuthKey(
log.Info().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("ips", strings.Join(machine.IPAddresses.StringSlice(), ", ")).
Str("node", registerRequest.Hostinfo.Hostname).
Str("ips", strings.Join(node.IPAddresses.StringSlice(), ", ")).
Msg("Successfully authenticated via AuthKey")
}
// handleNewMachine exposes for both legacy and Noise the functionality to get a URL
// for authorizing the machine. This url is then showed to the user by the local Tailscale client.
func (h *Headscale) handleNewMachine(
// handleNewNode exposes for both legacy and Noise the functionality to get a URL
// for authorizing the node. This url is then showed to the user by the local Tailscale client.
func (h *Headscale) handleNewNode(
writer http.ResponseWriter,
registerRequest tailcfg.RegisterRequest,
machineKey key.MachinePublic,
@ -449,11 +449,11 @@ func (h *Headscale) handleNewMachine(
) {
resp := tailcfg.RegisterResponse{}
// The machine registration is new, redirect the client to the registration URL
// The node registration is new, redirect the client to the registration URL
log.Debug().
Caller().
Bool("noise", isNoise).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Msg("The node seems to be new, sending auth url")
if h.oauth2Config != nil {
@ -495,13 +495,13 @@ func (h *Headscale) handleNewMachine(
Caller().
Bool("noise", isNoise).
Str("AuthURL", resp.AuthURL).
Str("machine", registerRequest.Hostinfo.Hostname).
Str("node", registerRequest.Hostinfo.Hostname).
Msg("Successfully sent auth url")
}
func (h *Headscale) handleMachineLogOut(
func (h *Headscale) handleNodeLogOut(
writer http.ResponseWriter,
machine types.Machine,
node types.Node,
machineKey key.MachinePublic,
isNoise bool,
) {
@ -509,17 +509,17 @@ func (h *Headscale) handleMachineLogOut(
log.Info().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Msg("Client requested logout")
now := time.Now()
err := h.db.MachineSetExpiry(&machine, now)
err := h.db.NodeSetExpiry(&node, now)
if err != nil {
log.Error().
Caller().
Bool("noise", isNoise).
Err(err).
Msg("Failed to expire machine")
Msg("Failed to expire node")
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
@ -528,7 +528,7 @@ func (h *Headscale) handleMachineLogOut(
resp.AuthURL = ""
resp.MachineAuthorized = false
resp.NodeKeyExpired = true
resp.User = *machine.User.TailscaleUser()
resp.User = *node.User.TailscaleUser()
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
if err != nil {
log.Error().
@ -554,13 +554,13 @@ func (h *Headscale) handleMachineLogOut(
return
}
if machine.IsEphemeral() {
err = h.db.DeleteMachine(&machine)
if node.IsEphemeral() {
err = h.db.DeleteNode(&node)
if err != nil {
log.Error().
Err(err).
Str("machine", machine.Hostname).
Msg("Cannot delete ephemeral machine from the database")
Str("node", node.Hostname).
Msg("Cannot delete ephemeral node from the database")
}
return
@ -569,29 +569,29 @@ func (h *Headscale) handleMachineLogOut(
log.Info().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Msg("Successfully logged out")
}
func (h *Headscale) handleMachineWithValidRegistration(
func (h *Headscale) handleNodeWithValidRegistration(
writer http.ResponseWriter,
machine types.Machine,
node types.Node,
machineKey key.MachinePublic,
isNoise bool,
) {
resp := tailcfg.RegisterResponse{}
// The machine registration is valid, respond with redirect to /map
// The node registration is valid, respond with redirect to /map
log.Debug().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Msg("Client is registered and we have the current NodeKey. All clear to /map")
resp.AuthURL = ""
resp.MachineAuthorized = true
resp.User = *machine.User.TailscaleUser()
resp.Login = *machine.User.TailscaleLogin()
resp.User = *node.User.TailscaleUser()
resp.Login = *node.User.TailscaleLogin()
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
if err != nil {
@ -600,13 +600,13 @@ func (h *Headscale) handleMachineWithValidRegistration(
Bool("noise", isNoise).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("update", "web", "error", machine.User.Name).
nodeRegistrations.WithLabelValues("update", "web", "error", node.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("update", "web", "success", machine.User.Name).
nodeRegistrations.WithLabelValues("update", "web", "success", node.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
@ -623,14 +623,14 @@ func (h *Headscale) handleMachineWithValidRegistration(
log.Info().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Msg("Machine successfully authorized")
Str("node", node.Hostname).
Msg("Node successfully authorized")
}
func (h *Headscale) handleMachineKeyRefresh(
func (h *Headscale) handleNodeKeyRefresh(
writer http.ResponseWriter,
registerRequest tailcfg.RegisterRequest,
machine types.Machine,
node types.Node,
machineKey key.MachinePublic,
isNoise bool,
) {
@ -639,10 +639,10 @@ func (h *Headscale) handleMachineKeyRefresh(
log.Info().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Msg("We have the OldNodeKey in the database. This is a key refresh")
err := h.db.MachineSetNodeKey(&machine, registerRequest.NodeKey)
err := h.db.NodeSetNodeKey(&node, registerRequest.NodeKey)
if err != nil {
log.Error().
Caller().
@ -654,7 +654,7 @@ func (h *Headscale) handleMachineKeyRefresh(
}
resp.AuthURL = ""
resp.User = *machine.User.TailscaleUser()
resp.User = *node.User.TailscaleUser()
respBody, err := mapper.MarshalResponse(resp, isNoise, h.privateKey2019, machineKey)
if err != nil {
log.Error().
@ -683,14 +683,14 @@ func (h *Headscale) handleMachineKeyRefresh(
Bool("noise", isNoise).
Str("node_key", registerRequest.NodeKey.ShortString()).
Str("old_node_key", registerRequest.OldNodeKey.ShortString()).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Msg("Node key successfully refreshed")
}
func (h *Headscale) handleMachineExpiredOrLoggedOut(
func (h *Headscale) handleNodeExpiredOrLoggedOut(
writer http.ResponseWriter,
registerRequest tailcfg.RegisterRequest,
machine types.Machine,
node types.Node,
machineKey key.MachinePublic,
isNoise bool,
) {
@ -706,11 +706,11 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
log.Trace().
Caller().
Bool("noise", isNoise).
Str("machine", machine.Hostname).
Str("node", node.Hostname).
Str("machine_key", machineKey.ShortString()).
Str("node_key", registerRequest.NodeKey.ShortString()).
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
Msg("Machine registration has expired or logged out. Sending a auth url to register")
Msg("Node registration has expired or logged out. Sending a auth url to register")
if h.oauth2Config != nil {
resp.AuthURL = fmt.Sprintf("%s/oidc/register/%s",
@ -729,13 +729,13 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
Bool("noise", isNoise).
Err(err).
Msg("Cannot encode message")
machineRegistrations.WithLabelValues("reauth", "web", "error", machine.User.Name).
nodeRegistrations.WithLabelValues("reauth", "web", "error", node.User.Name).
Inc()
http.Error(writer, "Internal server error", http.StatusInternalServerError)
return
}
machineRegistrations.WithLabelValues("reauth", "web", "success", machine.User.Name).
nodeRegistrations.WithLabelValues("reauth", "web", "success", node.User.Name).
Inc()
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
@ -755,6 +755,6 @@ func (h *Headscale) handleMachineExpiredOrLoggedOut(
Str("machine_key", machineKey.ShortString()).
Str("node_key", registerRequest.NodeKey.ShortString()).
Str("node_key_old", registerRequest.OldNodeKey.ShortString()).
Str("machine", machine.Hostname).
Msg("Machine logged out. Sent AuthURL for reauthentication")
Str("node", node.Hostname).
Msg("Node logged out. Sent AuthURL for reauthentication")
}