diff --git a/internal/db/dbModels/supertoken.go b/internal/db/dbModels/supertoken.go
index ec456eed97a4c6e6a10a056e20e8d976afa77153..1c21841d1b604d01bcdbac68a633e5c647afa2f0 100644
--- a/internal/db/dbModels/supertoken.go
+++ b/internal/db/dbModels/supertoken.go
@@ -6,6 +6,8 @@ import (
 	"log"
 	"time"
 
+	"github.com/zachmann/mytoken/internal/model"
+
 	"github.com/go-sql-driver/mysql"
 
 	"github.com/jmoiron/sqlx"
@@ -34,15 +36,17 @@ type SuperTokenEntry struct {
 	Name         string
 	CreatedAt    time.Time `db:"created_at"`
 	IP           string    `db:"ip_created"`
+	networkData  model.NetworkData
 }
 
-func NewSuperTokenEntry(name, oidcSub, oidcIss string, r restrictions.Restrictions, c capabilities.Capabilities, ip string) *SuperTokenEntry {
+func NewSuperTokenEntry(name, oidcSub, oidcIss string, r restrictions.Restrictions, c capabilities.Capabilities, networkData model.NetworkData) *SuperTokenEntry {
 	st := supertoken.NewSuperToken(oidcSub, oidcIss, r, c)
 	return &SuperTokenEntry{
-		ID:    st.ID,
-		Token: st,
-		Name:  name,
-		IP:    ip,
+		ID:          st.ID,
+		Token:       st,
+		Name:        name,
+		IP:          networkData.IP,
+		networkData: networkData,
 	}
 }
 
@@ -70,7 +74,7 @@ func (ste *SuperTokenEntry) Store(comment string) error {
 	if err != nil {
 		return err
 	}
-	return eventService.LogEvent(*event.FromNumber(event.STEventSTCreated, comment), ste.ID)
+	return eventService.LogEvent(*event.FromNumber(event.STEventSTCreated, comment), ste.ID, ste.networkData)
 }
 
 type superTokenEntryStore struct {
diff --git a/internal/endpoints/redirect/redirect.go b/internal/endpoints/redirect/redirect.go
index e0fd583842db28c662191130439c2e15b0373c15..04b5c37f0f45f1948a911cc571d5b099ff09cf65 100644
--- a/internal/endpoints/redirect/redirect.go
+++ b/internal/endpoints/redirect/redirect.go
@@ -28,6 +28,10 @@ func HandleOIDCRedirect(ctx *fiber.Ctx) error {
 		return errorRes.Send(ctx)
 	}
 	code := ctx.Query("code")
-	res := authcode.CodeExchange(state, code, ctx.IP())
+	networkData := model.NetworkData{
+		IP:        ctx.IP(),
+		UserAgent: string(ctx.Request().Header.UserAgent()),
+	}
+	res := authcode.CodeExchange(state, code, networkData)
 	return res.Send(ctx)
 }
diff --git a/internal/model/networkData.go b/internal/model/networkData.go
new file mode 100644
index 0000000000000000000000000000000000000000..f9532eacb4282938b407b6372eeeae488f969f32
--- /dev/null
+++ b/internal/model/networkData.go
@@ -0,0 +1,6 @@
+package model
+
+type NetworkData struct {
+	IP        string
+	UserAgent string
+}
diff --git a/internal/oidc/authcode/authcode.go b/internal/oidc/authcode/authcode.go
index 38ac1342e6a8d31e93caef06fb8aefbcae12c5fa..b0f0c56b760fccabd55fcb8d19b6ed297b366918 100644
--- a/internal/oidc/authcode/authcode.go
+++ b/internal/oidc/authcode/authcode.go
@@ -106,7 +106,7 @@ func InitAuthCodeFlow(provider *config.ProviderConf, req *response.AuthCodeFlowR
 	return
 }
 
-func CodeExchange(state, code, ip string) model.Response {
+func CodeExchange(state, code string, networkData model.NetworkData) model.Response {
 	log.Print("Handle code exchange")
 	authInfo, err := dbModels.GetAuthCodeInfoByState(state)
 	if err != nil {
@@ -152,13 +152,13 @@ func CodeExchange(state, code, ip string) model.Response {
 	if err != nil {
 		return model.ErrorToInternalServerErrorResponse(err)
 	}
-	ste, err := createSuperTokenEntry(authInfo, token, oidcSub, ip)
+	ste, err := createSuperTokenEntry(authInfo, token, oidcSub, networkData)
 	if err != nil {
 		return model.ErrorToInternalServerErrorResponse(err)
 	}
 	at := dbModels.AccessToken{
 		Token:     token.AccessToken,
-		IP:        ip,
+		IP:        networkData.IP,
 		Comment:   "Initial Access Token from authorization code flow",
 		STID:      ste.ID,
 		Scopes:    nil, //TODO
@@ -191,8 +191,8 @@ func CodeExchange(state, code, ip string) model.Response {
 	}
 }
 
-func createSuperTokenEntry(authFlowInfo *dbModels.AuthFlowInfo, token *oauth2.Token, oidcSub, ip string) (*dbModels.SuperTokenEntry, error) {
-	ste := dbModels.NewSuperTokenEntry(authFlowInfo.Name, oidcSub, authFlowInfo.Issuer, authFlowInfo.Restrictions, authFlowInfo.Capabilities, ip)
+func createSuperTokenEntry(authFlowInfo *dbModels.AuthFlowInfo, token *oauth2.Token, oidcSub string, networkData model.NetworkData) (*dbModels.SuperTokenEntry, error) {
+	ste := dbModels.NewSuperTokenEntry(authFlowInfo.Name, oidcSub, authFlowInfo.Issuer, authFlowInfo.Restrictions, authFlowInfo.Capabilities, networkData)
 	ste.RefreshToken = token.RefreshToken
 	err := ste.Store("Used grant_type oidc_flow authorization_code")
 	if err != nil {
diff --git a/internal/supertoken/event/event.go b/internal/supertoken/event/event.go
index 64a881f0c9e270556b05676574e8a97b852a7540..38e00a014cd70238f4cf56e08bf23192f5a1a906 100644
--- a/internal/supertoken/event/event.go
+++ b/internal/supertoken/event/event.go
@@ -3,16 +3,13 @@ package event
 import (
 	uuid "github.com/satori/go.uuid"
 	"github.com/zachmann/mytoken/internal/db"
+	"github.com/zachmann/mytoken/internal/model"
 	pkg "github.com/zachmann/mytoken/internal/supertoken/event/pkg"
 )
 
-func LogEvent(event pkg.Event, stid uuid.UUID) error {
-	//TODO
-	ip := "192.168.0.31"
-	userAgent := "go"
-
+func LogEvent(event pkg.Event, stid uuid.UUID, metaData model.NetworkData) error {
 	_, err := db.DB().Exec(`INSERT INTO ST_Events
 (ST_id, event_id, comment, ip, user_agent)
-VALUES(?, (SELECT id FROM Events WHERE event=?), ?, ?, ?)`, stid, event.String(), event.Comment, ip, userAgent)
+VALUES(?, (SELECT id FROM Events WHERE event=?), ?, ?, ?)`, stid, event.String(), event.Comment, metaData.IP, metaData.UserAgent)
 	return err
 }