nodemcu EEPROM corrupting
Look at this code:

void setupCredentials(const char *ssid, const char *password,
                      const char *link) {
  int addr = 0;

  EEPROM.begin(512);
  addr = sizeof(int);
  EEPROM.put(addr, ssid);
  delay(10);
  addr += sizeof(st_ssid);
  EEPROM.put(addr, password);
  delay(10);
  addr += sizeof(st_password);
  EEPROM.put(addr, link);
  delay(10);
  EEPROM.commit();


You are calling EEPROM.put(addr, ssid) with ssid being a const char*. A pointer to some memory location. Notice that you only give it a start address and a pointer, not the length of your data.

Have a look at the implementation of the put function:

  template&lt;typename T&gt; 
  const T &amp;put(int const address, const T &amp;t) {
    if (address &lt; 0 || address + sizeof(T) &gt; _size)
      return t;
    if (memcmp(_data + address, (const uint8_t*)&amp;t, sizeof(T)) != 0) {
      _dirty = true;
      memcpy(_data + address, (const uint8_t*)&amp;t, sizeof(T));
    }

    return t;
}


What it essentially does is copy your given object const T &amp;t into its internal _databuffer. The size of the data saved is determined by sizeof(T).

In your example t = ssid, T = const char* and sizeof(T) = sizeof(char*) = 4 and addr= sizeof(int) = 4. 

What you are doing here is not to save the string that ssid points to in memory but the pointer value of ssid. After you leave the function the data pointed to by ssid will be de-allocated at some point and the memory will be overwritten by something else.

When you do a print directly in the function you are retrieving the pointer value of ssid 3 times and print that value. At that point the data is still there and everything is okay. Then if you print it again after leaving the function you get garbage because the local data is gone after the function call handleSetup is left.

What you want here is to not use a const char* in your second argument to a  EEPROM.put(address, object) call but a char [20], for example. This way the put will work correctly.

Example:

// Assume EEPROM.begin() was called already
void EEPROM_SaveSSID(const int address, const char* str) {
    char ssid_buf[20];
    strncpy(ssid_buf, sizeof(ssid_buf) - 1, str);
    EEPROM.put&lt;char[20]&gt;(address, ssid_buf[0]); //sizeof(ssid_buf) = 20
    //don't forget to EEPROM.commit(); and EEPROM.end()
}

/* read SSID into a pre-allocated buffer */
void EEPROM_ReadSSID(const int address, char ssid_buf[20]) {
    EEPROM.get(address, ssid_buf); //sizeof(ssid_buf) = 20
}


If you do not like the semantics of these C++-templates auto-determining the size of read/write calls, you can always use bytewise read and write calls:

void EEPROM_SaveSSID(const int address, const char* str) {
    for(size_t i = 0; i &lt; strlen(str)) {
        EEPROM.write((int)(address + i), str[i]);
    }
}

/* always read 20 bytes starting from given address into buffer */
void EEPROM_ReadSSID(const int address, char ssid_buf[20]) {
    for(size_t i = 0; i &lt; sizeof(ssid_buf); i++) {
        ssid_buf[i] = EEPROM.read((int)(address + i));
    }
}


See "EEPROM" (actually: Flash-emulated EEPROM) implementation code at https://github.com/esp8266/Arduino/tree/master/libraries/EEPROM.