diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index cc0b999f4001d28c50db65fd8e1a49be540967fa..e67e0936dd5cc89213d315645d2ef47f3c765c23 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -36,6 +36,7 @@
         "libphonenumber-js": "^1.9.35",
         "lodash": "^4.17.21",
         "react": "^17.0.2",
+        "react-cookie": "^4.1.1",
         "react-dom": "^17.0.2",
         "react-helmet": "^6.1.0",
         "react-hook-form": "^7.17.5",
@@ -4222,6 +4223,11 @@
         "@babel/types": "^7.3.0"
       }
     },
+    "node_modules/@types/cookie": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
+      "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
+    },
     "node_modules/@types/eslint": {
       "version": "7.28.2",
       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz",
@@ -4258,6 +4264,15 @@
       "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz",
       "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ=="
     },
+    "node_modules/@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "dependencies": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "node_modules/@types/html-minifier-terser": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz",
@@ -18211,6 +18226,19 @@
         "node": ">=10"
       }
     },
+    "node_modules/react-cookie": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
+      "integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
+      "dependencies": {
+        "@types/hoist-non-react-statics": "^3.0.1",
+        "hoist-non-react-statics": "^3.0.0",
+        "universal-cookie": "^4.0.0"
+      },
+      "peerDependencies": {
+        "react": ">= 16.3.0"
+      }
+    },
     "node_modules/react-dev-utils": {
       "version": "11.0.4",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -21857,6 +21885,15 @@
         "node": ">=4"
       }
     },
+    "node_modules/universal-cookie": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
+      "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
+      "dependencies": {
+        "@types/cookie": "^0.3.3",
+        "cookie": "^0.4.0"
+      }
+    },
     "node_modules/universalify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
@@ -26973,6 +27010,11 @@
         "@babel/types": "^7.3.0"
       }
     },
+    "@types/cookie": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
+      "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
+    },
     "@types/eslint": {
       "version": "7.28.2",
       "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz",
@@ -27009,6 +27051,15 @@
       "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz",
       "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ=="
     },
+    "@types/hoist-non-react-statics": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
+      "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
+      "requires": {
+        "@types/react": "*",
+        "hoist-non-react-statics": "^3.3.0"
+      }
+    },
     "@types/html-minifier-terser": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz",
@@ -37821,6 +37872,16 @@
         "whatwg-fetch": "^3.4.1"
       }
     },
+    "react-cookie": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
+      "integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
+      "requires": {
+        "@types/hoist-non-react-statics": "^3.0.1",
+        "hoist-non-react-statics": "^3.0.0",
+        "universal-cookie": "^4.0.0"
+      }
+    },
     "react-dev-utils": {
       "version": "11.0.4",
       "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -40693,6 +40754,15 @@
         "crypto-random-string": "^1.0.0"
       }
     },
+    "universal-cookie": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
+      "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
+      "requires": {
+        "@types/cookie": "^0.3.3",
+        "cookie": "^0.4.0"
+      }
+    },
     "universalify": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 869252b77debd5493aaba95d2487a6a5d898b60a..6d3231eaec34e029ba288fd6d0cd58d054ea34d6 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -31,6 +31,7 @@
     "libphonenumber-js": "^1.9.35",
     "lodash": "^4.17.21",
     "react": "^17.0.2",
+    "react-cookie": "^4.1.1",
     "react-dom": "^17.0.2",
     "react-helmet": "^6.1.0",
     "react-hook-form": "^7.17.5",
diff --git a/frontend/src/contexts/userContext.ts b/frontend/src/contexts/userContext.ts
index 6fcc23f13aed02bfe0851de69151f29ae4cb38f8..ed0029453bb2f7ee438ed7338e42a8d442193dbe 100644
--- a/frontend/src/contexts/userContext.ts
+++ b/frontend/src/contexts/userContext.ts
@@ -12,6 +12,7 @@ function noop() {}
 export const UserContext = createContext<IUserContext>({
   user: {
     auth: false,
+    auth_type: '',
     fetched: false,
     first_name: '',
     last_name: '',
diff --git a/frontend/src/interfaces/index.ts b/frontend/src/interfaces/index.ts
index 9cd159ff4da87bee6e6eaa6a7544c8ad98e04bb5..ff8f15f2fd98049e1e14675df685966e4147f3d2 100644
--- a/frontend/src/interfaces/index.ts
+++ b/frontend/src/interfaces/index.ts
@@ -64,6 +64,7 @@ export type FetchedRole = {
 
 export interface User {
   auth: boolean
+  auth_type: string
   fetched: boolean
   person_id: string
   sponsor_id: string
diff --git a/frontend/src/providers/userProvider.tsx b/frontend/src/providers/userProvider.tsx
index 2d1d17a18fa6ccfb7f0841b0ef3699fef588f64c..3a17e9d8e231791ab137fa8685929ed0e55c9565 100644
--- a/frontend/src/providers/userProvider.tsx
+++ b/frontend/src/providers/userProvider.tsx
@@ -10,6 +10,7 @@ function UserProvider(props: UserProviderProps) {
   const { children } = props
   const [user, setUser] = useState({
     auth: false,
+    auth_type: '',
     fetched: false,
     first_name: '',
     last_name: '',
@@ -31,6 +32,7 @@ function UserProvider(props: UserProviderProps) {
       if (response.ok) {
         setUser({
           auth: true,
+          auth_type: data.auth_type,
           fetched: true,
           first_name: data.first_name,
           last_name: data.last_name,
@@ -46,6 +48,7 @@ function UserProvider(props: UserProviderProps) {
       } else {
         setUser({
           auth: false,
+          auth_type: '',
           fetched: true,
           first_name: '',
           last_name: '',
@@ -62,6 +65,7 @@ function UserProvider(props: UserProviderProps) {
     } catch (error) {
       setUser({
         auth: false,
+        auth_type: '',
         fetched: true,
         first_name: '',
         last_name: '',
@@ -92,6 +96,7 @@ function UserProvider(props: UserProviderProps) {
   const clearUserInfo = () => {
     setUser({
       auth: false,
+      auth_type: '',
       fetched: false,
       first_name: '',
       last_name: '',
diff --git a/frontend/src/routes/components/header.tsx b/frontend/src/routes/components/header.tsx
index b69c4782854eaa0fd04a661f938d2f4d3d29bbbb..7b64b4233ae3c983d8300ef7cce52e2fcd325e66 100644
--- a/frontend/src/routes/components/header.tsx
+++ b/frontend/src/routes/components/header.tsx
@@ -48,6 +48,9 @@ const Header = () => {
   const { user } = useUserContext()
   const { t } = useTranslation('common')
 
+  const logoutLink =
+    user.auth_type === 'oidc' ? '/oidc/logout' : '/invite/logout'
+
   return (
     <StyledHeader>
       <MainContainer>
@@ -61,7 +64,7 @@ const Header = () => {
                 sx={{
                   color: 'white',
                 }}
-                href="/oidc/logout"
+                href={logoutLink}
               >
                 {t('button.logout')}
                 <LogoutIcon
diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx
index edb75c2226b1b231d03e68737cb53d251135004c..e273442a88500c9057310d7a663a4b068b2be86d 100644
--- a/frontend/src/routes/index.tsx
+++ b/frontend/src/routes/index.tsx
@@ -13,6 +13,7 @@ import Register from 'routes/sponsor/register'
 import FrontPage from 'routes/frontpage'
 import Invite from 'routes/invite'
 import InviteLink from 'routes/invitelink'
+import LogoutInviteSession from 'routes/invitelink/logout'
 import Footer from 'routes/components/footer'
 import Header from 'routes/components/header'
 import NotFound from 'routes/components/notFound'
@@ -77,6 +78,7 @@ export default function App() {
             <Register />
           </ProtectedRoute>
           <Route path="/invitelink/" component={InviteLink} />
+          <Route path="/invite/logout" component={LogoutInviteSession} />
           <Route path="/invite/" component={Invite} />
           <Route path="/guestregister" component={GuestRegister} />
           <Route>
diff --git a/frontend/src/routes/invitelink/logout.tsx b/frontend/src/routes/invitelink/logout.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..f0333dde0bfbb80a3d68fc6b5e3c9f8a7fd93ae1
--- /dev/null
+++ b/frontend/src/routes/invitelink/logout.tsx
@@ -0,0 +1,31 @@
+import { useEffect, useState } from 'react'
+import { Redirect } from 'react-router-dom'
+import { useCookies } from 'react-cookie'
+
+import { Box, CircularProgress } from '@mui/material'
+
+import { useUserContext } from 'contexts'
+
+export default function LogoutInviteSession() {
+  // Fetch backend endpoint to preserve invite_id in backend session then redirect
+  const [, , removeCookie] = useCookies(['sessionid'])
+  const [loggedOut, setLoggedOut] = useState(false)
+  const { fetchUserInfo } = useUserContext()
+
+  useEffect(() => {
+    fetch('/api/ui/v1/invitecheck/', { method: 'DELETE' })
+      .then(() => removeCookie('sessionid'))
+      .then(() => fetchUserInfo())
+      .then(() => setLoggedOut(true))
+  }, [])
+
+  if (loggedOut) {
+    return <Redirect to="/" />
+  }
+
+  return (
+    <Box sx={{ margin: 'auto' }}>
+      <CircularProgress />
+    </Box>
+  )
+}
diff --git a/gregui/api/views/invitation.py b/gregui/api/views/invitation.py
index 2a36d024a488fcec3e01ec1d115bb9fd408143f3..a979d534b95357fe0a02a5e5ee7efb2275dda1a7 100644
--- a/gregui/api/views/invitation.py
+++ b/gregui/api/views/invitation.py
@@ -1,6 +1,6 @@
-import logging
 from enum import Enum
 from typing import Optional, List
+import structlog
 
 from django.core import exceptions
 from django.db import transaction
@@ -24,7 +24,7 @@ from gregui.api.serializers.invitation import InviteGuestSerializer
 from gregui.mailutils import send_invite_mail
 from gregui.models import GregUserProfile
 
-logger = logging.getLogger(__name__)
+logger = structlog.getLogger(__name__)
 
 
 class InvitationView(CreateAPIView, DestroyAPIView):
@@ -91,9 +91,7 @@ class InvitationView(CreateAPIView, DestroyAPIView):
             # not be verified, but including that check just in case here.
             # If this is the case then there is an unexpected situation, the cancel option
             # should only apply to guests that have not completed the registration
-            logger.warning(
-                f"Attempting to delete invitation for already registered guest with person ID {person_id}"
-            )
+            logger.warning("try_delete_registered_invite", person_id=person_id)
             return Response(status=status.HTTP_400_BAD_REQUEST)
 
         # Delete the person. The delete will cascade and all roles, identities and invitations will be removed.
@@ -109,7 +107,7 @@ class CheckInvitationView(APIView):
     permission_classes = [AllowAny]
     throttle_classes = [AnonRateThrottle]
 
-    def post(self, request, *args, **kwargs):
+    def post(self, request, *args, **kwargs) -> Response:
         """
         Endpoint for verifying and setting invite_id in session.
 
@@ -132,6 +130,16 @@ class CheckInvitationView(APIView):
         request.session["invite_id"] = invite_id
         return Response(status=status.HTTP_200_OK)
 
+    def delete(self, request, *args, **kwargs) -> Response:
+        if "invite_id" in request.session:
+            logger.info(
+                "invitation_session_deleted", invite_id=request.session["invite_id"]
+            )
+            del request.session["invite_id"]
+            return Response(status.HTTP_200_OK)
+
+        return Response(status=status.HTTP_403_FORBIDDEN)
+
 
 class SessionType(Enum):
     INVITE = "invite"
@@ -322,9 +330,7 @@ class ResendInvitationView(UpdateModelMixin, APIView):
         if non_expired_links.count() > 0:
             if non_expired_links.count() > 1:
                 # Do not expect this to happen
-                logger.warning(
-                    f"Person with ID {person_id} has multiple invitation links"
-                )
+                logger.warning("found_multiple_invitation_links", person_id=person_id)
 
             # Just resend all and do not create a new one
             for link in non_expired_links:
@@ -339,9 +345,7 @@ class ResendInvitationView(UpdateModelMixin, APIView):
                 # Do not expected that a person has several open invitations, it could happen
                 # if he has been invited by different sponsor at the same time, but that
                 # could be an indication that there has been a mixup
-                logger.warning(
-                    f"Multiple invitations exist for person with ID {person_id}"
-                )
+                logger.warning("found_multiple_invitations", person_id=person_id)
 
             for invitation in invitations_to_resend:
                 invitation_link = InvitationLink.objects.create(
diff --git a/gregui/api/views/userinfo.py b/gregui/api/views/userinfo.py
index b2e17997d1c50815c546f824839438480e9f9425..bba967c519e0c611d7018bd651a47c35bd984d96 100644
--- a/gregui/api/views/userinfo.py
+++ b/gregui/api/views/userinfo.py
@@ -34,6 +34,10 @@ class UserInfoView(APIView):
         user = request.user
         invite_id = request.session.get("invite_id")
 
+        auth_type = "invite"
+        if "oidc_states" in request.session.keys():
+            auth_type = "oidc"
+
         person = None
         sponsor = None
         content = {
@@ -41,6 +45,7 @@ class UserInfoView(APIView):
             "sponsor_id": None,
             "person_id": None,
             "roles": [],
+            "auth_type": auth_type,
         }
 
         # Fetch sponsor and/or person object from profile of authenticated user
diff --git a/gregui/tests/api/views/test_userinfo.py b/gregui/tests/api/views/test_userinfo.py
index 8b615661adab101b74bc49da74e4f19551b62b28..cf1f331d48c6ff3ca1fe2d2ec47f4db756ac7c68 100644
--- a/gregui/tests/api/views/test_userinfo.py
+++ b/gregui/tests/api/views/test_userinfo.py
@@ -19,6 +19,7 @@ def test_userinfo_invited_get(client, invitation_link):
     response = client.get(reverse("api-userinfo"))
     assert response.status_code == status.HTTP_200_OK
     assert response.json() == {
+        "auth_type": "invite",
         "feide_id": None,
         "sponsor_id": None,
         "person_id": 1,
@@ -59,6 +60,7 @@ def test_userinfo_sponsor_get(client, log_in, user_sponsor):
     response = client.get(reverse("api-userinfo"))
     assert response.status_code == status.HTTP_200_OK
     assert response.json() == {
+        "auth_type": "oidc",
         "feide_id": "",
         "person_id": None,
         "roles": [],
@@ -73,6 +75,7 @@ def test_userinfo_guest_get(client, log_in, user_person):
     response = client.get(reverse("api-userinfo"))
     assert response.status_code == status.HTTP_200_OK
     assert response.json() == {
+        "auth_type": "oidc",
         "feide_id": "",
         "sponsor_id": None,
         "person_id": 1,
diff --git a/gregui/tests/conftest.py b/gregui/tests/conftest.py
index c7e5d52ac930def1bce5b3ddde659a4b5891dcc4..8386752d53ad86292066851b8324c80d8b2e4a30 100644
--- a/gregui/tests/conftest.py
+++ b/gregui/tests/conftest.py
@@ -471,6 +471,7 @@ def log_in(client) -> Callable[[UserModel], APIClient]:
         # It seems like the session was not updated automatically this way
         session = client.session
         session["oidc_id_token_payload"] = {"iat": time.time()}
+        session["oidc_states"] = {}
         session.save()
         return client