Embeddings are essentially just a lookup table from integers to vector representations. These representations are learned during the pretraining process like any other parameter in the language model.
That is, they are initialized randomly then, as the model trains during pretraining (typically with some next-token prediction or denoising objective), gradients are propagated back to the embedding lookup table. Just as the regular parameters change to allow the model to predict tokens effectively, the token representations will also change to become more "meaningful" for the model.
If you further finetune the model, you use the existing pretrained parameters of the model, including the token embedding representations. Like any other parameter in the model, you can then choose to freeze or finetune the token embeddings as well.
You should just think of token embeddings like any other parameter in the model. Although there are other kinds of token embeddings (e.g., word2vec), in the context of large language model training, I'm not aware of any other initialization method other than what I described above, other than some niche scenarios (e.g., cross-lingual transfer: 1, 2, 3).
If you want a code example, you can take a look at the Embedding class in PyTorch.