diff --git a/js/src/components/Event/Date.vue b/js/src/components/Event/Date.vue
new file mode 100644
index 000000000..c8ae190c6
--- /dev/null
+++ b/js/src/components/Event/Date.vue
@@ -0,0 +1,54 @@
+<template>
+    <span class="container">
+        <span class="month">{{ month }}</span>
+        <span class="day">{{ day }}</span>
+    </span>
+</template>
+<script lang="ts">
+import { Component, Prop, Vue } from 'vue-property-decorator';
+
+@Component
+export default class DateComponent extends Vue {
+  @Prop({ required: true }) date!: string;
+
+  get dateObj() {
+      return new Date(this.$props.date);
+  }
+
+  get month() {
+    return this.dateObj.toLocaleString(undefined, { month: 'short' });
+  }
+
+  get day() {
+    return this.dateObj.toLocaleString(undefined, { day: 'numeric' });
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .container {
+    display: inline-flex;
+    padding: 2px 0;
+    width: 40px;
+    background: #fff;
+
+    span {
+      flex: 0;
+      flex-direction: column;
+      text-align: center;
+
+      &.month {
+        color: #fa3e3e;
+        padding: 2px 0;
+        font-size: 12px;
+        line-height: 12px;
+      }
+
+      &.day {
+        font-weight: 300;
+        font-size: 20px;
+        line-height: 20px;
+      }
+    }
+  }
+</style>
diff --git a/js/src/components/Event/EventCard.vue b/js/src/components/Event/EventCard.vue
index 9023e1679..d1bfd38f4 100644
--- a/js/src/components/Event/EventCard.vue
+++ b/js/src/components/Event/EventCard.vue
@@ -1,8 +1,8 @@
 <template>
   <div class="card">
     <div class="card-image" v-if="!event.image">
-      <figure class="image is-4by3">
-        <img src="https://picsum.photos/g/400/200/">
+      <figure class="image is-16by9">
+        <img src="https://picsum.photos/g/400/225/?random">
       </figure>
     </div>
     <div class="card-content">
@@ -10,12 +10,17 @@
         <router-link :to="{ name: 'Event', params:{ uuid: event.uuid } }">
           <h2 class="title">{{ event.title }}</h2>
         </router-link>
-        <span>{{ event.beginsOn | formatDay }}</span>
+        <DateComponent v-if="!options.hideDate" :date="event.beginsOn" />
       </div>
-      <div v-if="!hideDetails">
-        <div v-if="event.participants.length === 1">
+      <div v-if="!options.hideDetails">
+        <div v-if="event.participants.length > 0 &&
+        options.loggedPerson &&
+        event.participants[0].actor.id === options.loggedPerson.id">
+          <b-tag type="is-info"><translate>Organizer</translate></b-tag>
+        </div>
+        <div v-else-if="event.participants.length === 1">
           <translate
-            :translate-params="{name: event.participants[0].actor.preferredUsername}"
+                  :translate-params="{name: event.participants[0].actor.preferredUsername}"
           >%{name} organizes this event</translate>
         </div>
         <div v-else>
@@ -35,11 +40,17 @@
 <script lang="ts">
 import { IEvent, ParticipantRole } from '@/types/event.model';
 import { Component, Prop, Vue } from 'vue-property-decorator';
+import DateComponent from '@/components/Event/Date.vue';
 
-@Component
+@Component({
+  components: {
+    DateComponent,
+    EventCard,
+  },
+})
 export default class EventCard extends Vue {
   @Prop({ required: true }) event!: IEvent;
-  @Prop({ default: false }) hideDetails!: boolean;
+  @Prop({ default() { return { hideDate: false, loggedPerson: false, hideDetails: false }; } }) options!: object;
 
   data() {
     return {
diff --git a/js/src/components/NavBar.vue b/js/src/components/NavBar.vue
index 967995037..4c977329e 100644
--- a/js/src/components/NavBar.vue
+++ b/js/src/components/NavBar.vue
@@ -75,8 +75,8 @@ import { ICurrentUser } from '@/types/current-user.model'
     },
     config: {
       query: CONFIG,
-    }
-  }
+    },
+  },
 })
 export default class NavBar extends Vue {
   notifications = [
diff --git a/js/src/graphql/actor.ts b/js/src/graphql/actor.ts
index 5167e7ff6..9d43ad06d 100644
--- a/js/src/graphql/actor.ts
+++ b/js/src/graphql/actor.ts
@@ -3,6 +3,7 @@ import gql from 'graphql-tag';
 export const FETCH_PERSON = gql`
 query($name:String!) {
   person(preferredUsername: $name) {
+    id,
     url,
     name,
     domain,
@@ -11,9 +12,13 @@ query($name:String!) {
     suspended,
     avatarUrl,
     bannerUrl,
+    feedTokens {
+        token
+    },
     organizedEvents {
         uuid,
-        title
+        title,
+        beginsOn
     },
   }
 }
@@ -28,6 +33,26 @@ query {
   }
 }`;
 
+export const LOGGED_PERSON_WITH_GOING_TO_EVENTS = gql`
+query {
+  loggedPerson {
+    id,
+    avatarUrl,
+    preferredUsername,
+    goingToEvents {
+        uuid,
+        title,
+        beginsOn,
+        participants {
+            actor {
+                id,
+                preferredUsername
+            }
+        }
+    },
+  }
+}`;
+
 export const IDENTITIES = gql`
 query {
   identities {
diff --git a/js/src/graphql/feed_tokens.ts b/js/src/graphql/feed_tokens.ts
new file mode 100644
index 000000000..f7659b521
--- /dev/null
+++ b/js/src/graphql/feed_tokens.ts
@@ -0,0 +1,49 @@
+import gql from 'graphql-tag';
+
+export const LOGGED_PERSON = gql`
+query {
+  loggedPerson {
+    id,
+    avatarUrl,
+    preferredUsername,
+  }
+}`;
+
+export const CREATE_FEED_TOKEN_ACTOR = gql`
+mutation createFeedToken($actor_id: Int!) {
+  createFeedToken(actor_id: $actor_id) {
+    token,
+    actor {
+      id
+    },
+    user {
+      id
+    }
+  }
+}`;
+
+export const CREATE_FEED_TOKEN = gql`
+mutation {
+  createFeedToken {
+    token,
+    actor {
+      id
+    },
+    user {
+      id
+    }
+  }
+}`;
+
+export const DELETE_FEED_TOKEN = gql`
+mutation deleteFeedToken($token: String!) {
+    deleteFeedToken(token: $token) {
+        actor {
+          id
+        },
+        user {
+          id
+        }
+      }
+    }
+`;
diff --git a/js/src/types/actor.model.ts b/js/src/types/actor.model.ts
index 749e59e25..62a3c8af8 100644
--- a/js/src/types/actor.model.ts
+++ b/js/src/types/actor.model.ts
@@ -1,3 +1,6 @@
+import { ICurrentUser } from '@/types/current-user.model';
+import { IEvent } from '@/types/event.model';
+
 export interface IActor {
   id?: string;
   url: string;
@@ -22,14 +25,24 @@ export class Actor implements IActor {
 }
 
 export interface IPerson extends IActor {
-
+  feedTokens: IFeedToken[];
+  goingToEvents: IEvent[];
 }
 
 export interface IGroup extends IActor {
   members: IMember[];
 }
 
-export class Person extends Actor implements IPerson {}
+export class Person extends Actor implements IPerson {
+  feedTokens: IFeedToken[] = [];
+  goingToEvents: IEvent[] = [];
+}
+
+export interface IFeedToken {
+  token: string;
+  actor?: IPerson;
+  user: ICurrentUser;
+}
 
 export enum MemberRole {
   PENDING,
diff --git a/js/src/types/config.model.ts b/js/src/types/config.model.ts
index 78ff7d284..05dc42a3c 100644
--- a/js/src/types/config.model.ts
+++ b/js/src/types/config.model.ts
@@ -1,5 +1,5 @@
 export interface IConfig {
-  name: string,
+  name: string;
 
-  registrationsOpen: boolean,
+  registrationsOpen: boolean;
 }
diff --git a/js/src/views/Account/Profile.vue b/js/src/views/Account/Profile.vue
index 628fbd9b1..481e7b348 100644
--- a/js/src/views/Account/Profile.vue
+++ b/js/src/views/Account/Profile.vue
@@ -1,68 +1,107 @@
 <template>
-  <section>
-    <div class="columns">
-      <div class="column">
-        <div class="card" v-if="person">
-          <div class="card-image" v-if="person.bannerUrl">
-            <figure class="image">
-              <img :src="person.bannerUrl">
-            </figure>
-          </div>
-          <div class="card-content">
-            <div class="media">
-              <div class="media-left">
-                <figure class="image is-48x48">
-                  <img :src="person.avatarUrl">
-                </figure>
-              </div>
-              <div class="media-content">
-                <p class="title">{{ person.name }}</p>
-                <p class="subtitle">@{{ person.preferredUsername }}</p>
-              </div>
-            </div>
+    <section>
+        <div class="columns">
+            <div class="column">
+                <div class="card" v-if="person">
+                    <div class="card-image" v-if="person.bannerUrl">
+                        <figure class="image">
+                            <img :src="person.bannerUrl">
+                        </figure>
+                    </div>
+                    <div class="card-content">
+                        <div class="media">
+                            <div class="media-left">
+                                <figure class="image is-48x48">
+                                    <img :src="person.avatarUrl">
+                                </figure>
+                            </div>
+                            <div class="media-content">
+                                <p class="title">{{ person.name }}</p>
+                                <p class="subtitle">@{{ person.preferredUsername }}</p>
+                            </div>
+                        </div>
 
-            <div class="content">
-              <p v-html="person.summary"></p>
+                        <div class="content">
+                            <p v-html="person.summary"></p>
+                        </div>
+
+                        <b-dropdown hoverable has-link aria-role="list">
+                            <button class="button is-info" slot="trigger">
+                                <translate>Public feeds</translate>
+                                <b-icon icon="menu-down"></b-icon>
+                            </button>
+
+                            <b-dropdown-item aria-role="listitem">
+                                <a :href="feedUrls('atom', true)">
+                                    <translate>Public RSS/Atom Feed</translate>
+                                </a>
+                            </b-dropdown-item>
+                            <b-dropdown-item aria-role="listitem">
+                                <a :href="feedUrls('ics', true)">
+                                    <translate>Public iCal Feed</translate>
+                                </a>
+                            </b-dropdown-item>
+                        </b-dropdown>
+
+                        <b-dropdown hoverable has-link aria-role="list" v-if="person.feedTokens.length > 0">
+                            <button class="button is-info" slot="trigger">
+                                <translate>Private feeds</translate>
+                                <b-icon icon="menu-down"></b-icon>
+                            </button>
+
+                            <b-dropdown-item aria-role="listitem">
+                                <a :href="feedUrls('atom', false)">
+                                    <translate>RSS/Atom Feed</translate>
+                                </a>
+                            </b-dropdown-item>
+                            <b-dropdown-item aria-role="listitem">
+                                <a :href="feedUrls('ics', false)">
+                                    <translate>iCal Feed</translate>
+                                </a>
+                            </b-dropdown-item>
+                        </b-dropdown>
+                        <a class="button" v-else @click="createToken">
+                            <translate>Create token</translate>
+                        </a>
+                    </div>
+                    <section v-if="person.organizedEvents.length > 0">
+                        <h2 class="subtitle">
+                            <translate>Organized</translate>
+                        </h2>
+                        <div class="columns">
+                            <EventCard
+                                    v-for="event in person.organizedEvents"
+                                    :event="event"
+                                    :options="{ hideDetails: true }"
+                                    :key="event.uuid"
+                                    class="column is-one-third"
+                            />
+                        </div>
+                        <div class="field is-grouped">
+                            <p class="control">
+                                <a
+                                        class="button"
+                                        @click="logoutUser()"
+                                        v-if="loggedPerson && loggedPerson.id === person.id"
+                                >
+                                    <translate>User logout</translate>
+                                </a>
+                            </p>
+                            <p class="control">
+                                <a
+                                        class="button"
+                                        @click="deleteProfile()"
+                                        v-if="loggedPerson && loggedPerson.id === person.id"
+                                >
+                                    <translate>Delete</translate>
+                                </a>
+                            </p>
+                        </div>
+                    </section>
+                </div>
             </div>
-          </div>
-          <section v-if="person.organizedEvents.length > 0">
-            <h2 class="subtitle">
-              <translate>Organized</translate>
-            </h2>
-            <div class="columns">
-              <EventCard
-                v-for="event in person.organizedEvents"
-                :event="event"
-                :hideDetails="true"
-                :key="event.uuid"
-                class="column is-one-third"
-              />
-            </div>
-            <div class="field is-grouped">
-              <p class="control">
-                <a
-                  class="button"
-                  @click="logoutUser()"
-                  v-if="loggedPerson && loggedPerson.id === person.id"
-                >
-                  <translate>User logout</translate>
-                </a>
-              </p>
-              <p class="control">
-                <a
-                  class="button"
-                  @click="deleteProfile()"
-                  v-if="loggedPerson && loggedPerson.id === person.id"
-                >
-                  <translate>Delete</translate>
-                </a>
-              </p>
-            </div>
-          </section>
         </div>
-      </div>
-    </div>
-  </section>
+    </section>
 </template>
 
 <script lang="ts">
@@ -70,6 +109,9 @@ import { FETCH_PERSON, LOGGED_PERSON } from '@/graphql/actor';
 import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
 import EventCard from '@/components/Event/EventCard.vue';
 import { RouteName } from '@/router';
+import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint';
+import { IPerson } from '@/types/actor.model';
+import { CREATE_FEED_TOKEN_ACTOR } from '@/graphql/feed_tokens';
 
 @Component({
   apollo: {
@@ -92,21 +134,41 @@ import { RouteName } from '@/router';
 export default class Profile extends Vue {
   @Prop({ type: String, required: true }) name!: string;
 
-  person = null;
+  person!: IPerson;
 
-  // call again the method if the route changes
+    // call again the method if the route changes
   @Watch('$route')
-  onRouteChange() {
-    // this.fetchData()
+    onRouteChange() {
+        // this.fetchData()
   }
 
   logoutUser() {
-    // TODO : implement logout
+        // TODO : implement logout
     this.$router.push({ name: RouteName.HOME });
   }
 
   nl2br(text) {
     return text.replace(/(?:\r\n|\r|\n)/g, '<br>');
   }
+
+  feedUrls(format, isPublic = true): string {
+    let url = format === 'ics' ? 'webcal:' : '';
+    url += `//${MOBILIZON_INSTANCE_HOST}/`;
+    if (isPublic === true) {
+      url += `@${this.person.preferredUsername}/feed/`;
+    } else {
+      url += `events/going/${this.person.feedTokens[0].token}/`;
+    }
+    return url + (format === 'ics' ? 'ics' : 'atom');
+  }
+
+  async createToken() {
+    const { data } = await this.$apollo.mutate({
+      mutation: CREATE_FEED_TOKEN_ACTOR,
+      variables: { actor_id: this.person.id },
+    });
+
+    this.person.feedTokens.push(data);
+  }
 }
 </script>
diff --git a/js/src/views/Account/Register.vue b/js/src/views/Account/Register.vue
index b872b6290..3c125d9b6 100644
--- a/js/src/views/Account/Register.vue
+++ b/js/src/views/Account/Register.vue
@@ -93,6 +93,8 @@ export default class Register extends Vue {
     avatarUrl: '',
     bannerUrl: '',
     domain: null,
+    feedTokens: [],
+    goingToEvents: [],
   };
   errors: object = {};
   validationSent: boolean = false;
diff --git a/js/src/views/Event/Event.vue b/js/src/views/Event/Event.vue
index c3acf532b..436b378ca 100644
--- a/js/src/views/Event/Event.vue
+++ b/js/src/views/Event/Event.vue
@@ -107,6 +107,7 @@ import { IEvent, IParticipant } from '@/types/event.model';
 import { IPerson } from '@/types/actor.model';
 import { RouteName } from '@/router';
 import 'vue-simple-markdown/dist/vue-simple-markdown.css';
+import { GRAPHQL_API_ENDPOINT } from '@/api/_entrypoint';
 
 @Component({
   apollo: {
@@ -199,19 +200,15 @@ export default class Event extends Vue {
     }
   }
 
-  downloadIcsEvent() {
-    // FIXME: remove eventFetch
-    // eventFetch(`/events/${this.uuid}/ics`, this.$store, { responseType: 'arraybuffer' })
-    //   .then(response => response.text())
-    //   .then((response) => {
-    //     const blob = new Blob([ response ], { type: 'text/calendar' });
-    //     const link = document.createElement('a');
-    //     link.href = window.URL.createObjectURL(blob);
-    //     link.download = `${this.event.title}.ics`;
-    //     document.body.appendChild(link);
-    //     link.click();
-    //     document.body.removeChild(link);
-    //   });
+  async downloadIcsEvent() {
+    const data = await (await fetch(`${GRAPHQL_API_ENDPOINT}/events/${this.uuid}/export/ics`)).text();
+    const blob = new Blob([data], { type: 'text/calendar' });
+    const link = document.createElement('a');
+    link.href = window.URL.createObjectURL(blob);
+    link.download = `${this.event.title}.ics`;
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
   }
 
   actorIsParticipant() {
diff --git a/js/src/views/Group/Group.vue b/js/src/views/Group/Group.vue
index 29cb47aa8..b755a4811 100644
--- a/js/src/views/Group/Group.vue
+++ b/js/src/views/Group/Group.vue
@@ -33,7 +33,7 @@
               <EventCard
                 v-for="event in group.organizedEvents"
                 :event="event"
-                :hideDetails="true"
+                :options="{ hideDetails: true }"
                 :key="event.uuid"
                 class="column is-one-third"
               />
diff --git a/js/src/views/Home.vue b/js/src/views/Home.vue
index 25a6fb911..e3aa5848d 100644
--- a/js/src/views/Home.vue
+++ b/js/src/views/Home.vue
@@ -18,6 +18,50 @@
         >Welcome back %{username}</translate>
       </h1>
     </section>
+    <section v-if="loggedPerson">
+      <span class="events-nearby title">Events you're going at</span>
+      <b-loading :active.sync="$apollo.loading"></b-loading>
+      <div v-if="goingToEvents.size > 0" v-for="row in Array.from(goingToEvents.entries())">
+        <!--   Iterators will be supported in v-for with VueJS 3     -->
+        <date-component :date="row[0]"></date-component>
+          <h3 class="subtitle"
+            v-if="isToday(row[0])"
+            v-translate="{count: row[1].length}"
+            :translate-n="row[1].length"
+            translate-plural="You have %{ count } events today"
+          >
+                  You have one event today.
+          </h3>
+          <h3 class="subtitle"
+              v-else-if="isTomorrow(row[0])"
+              v-translate="{count: row[1].length}"
+              :translate-n="row[1].length"
+              translate-plural="You have %{ count } events tomorrow"
+          >
+              You have one event tomorrow.
+          </h3>
+          <h3 class="subtitle"
+              v-else
+              v-translate="{count: row[1].length, days: calculateDiffDays(row[0])}"
+              :translate-n="row[1].length"
+              translate-plural="You have %{ count } events in %{ days } days"
+          >
+              You have one event in %{ days } days.
+          </h3>
+        <div class="columns">
+          <EventCard
+                  v-for="event in row[1]"
+                  :key="event.uuid"
+                  :event="event"
+                  :options="{loggedPerson: loggedPerson}"
+                  class="column is-one-quarter-desktop is-half-mobile"
+          />
+        </div>
+      </div>
+      <b-message v-else type="is-danger">
+        <translate>You're not going to any event yet</translate>
+      </b-message>
+    </section>
     <section>
       <span class="events-nearby title">Events nearby you</span>
       <b-loading :active.sync="$apollo.loading"></b-loading>
@@ -41,11 +85,13 @@ import ngeohash from 'ngeohash';
 import { FETCH_EVENTS } from '@/graphql/event';
 import { Component, Vue } from 'vue-property-decorator';
 import EventCard from '@/components/Event/EventCard.vue';
-import { LOGGED_PERSON } from '@/graphql/actor';
-import { IPerson } from '@/types/actor.model';
+import { LOGGED_PERSON_WITH_GOING_TO_EVENTS } from '@/graphql/actor';
+import { IPerson, Person } from '@/types/actor.model';
 import { ICurrentUser } from '@/types/current-user.model';
 import { CURRENT_USER_CLIENT } from '@/graphql/user';
 import { RouteName } from '@/router';
+import { IEvent } from '@/types/event.model';
+import DateComponent from '@/components/Event/Date.vue';
 
 @Component({
   apollo: {
@@ -54,13 +100,14 @@ import { RouteName } from '@/router';
       fetchPolicy: 'no-cache', // Debug me: https://github.com/apollographql/apollo-client/issues/3030
     },
     loggedPerson: {
-      query: LOGGED_PERSON,
+      query: LOGGED_PERSON_WITH_GOING_TO_EVENTS,
     },
     currentUser: {
       query: CURRENT_USER_CLIENT,
     },
   },
   components: {
+    DateComponent,
     EventCard,
   },
 })
@@ -69,8 +116,7 @@ export default class Home extends Vue {
   locations = [];
   city = { name: null };
   country = { name: null };
-  // FIXME: correctly parse local storage
-  loggedPerson!: IPerson;
+  loggedPerson: IPerson = new Person();
   currentUser!: ICurrentUser;
 
   get displayed_name() {
@@ -79,13 +125,47 @@ export default class Home extends Vue {
       : this.loggedPerson.name;
   }
 
-  fetchLocations() {
-    // FIXME: remove eventFetch
-    // eventFetch('/locations', this.$store)
-    //   .then(response => (response.json()))
-    //   .then((response) => {
-    //     this.locations = response;
-    //   });
+  isToday(date: string) {
+    return (new Date(date)).toDateString() === (new Date()).toDateString();
+  }
+
+  isTomorrow(date: string) :boolean {
+    return this.isInDays(date, 1);
+  }
+
+  isInDays(date: string, nbDays: number) :boolean {
+    return this.calculateDiffDays(date) === nbDays;
+  }
+
+  isBefore(date: string, nbDays: number) :boolean {
+    return this.calculateDiffDays(date) > nbDays;
+  }
+
+  // FIXME: Use me
+  isInLessThanSevenDays(date: string): boolean {
+    return this.isInDays(date, 7);
+  }
+
+  calculateDiffDays(date: string): number {
+    const dateObj = new Date(date);
+    return Math.ceil((dateObj.getTime() - (new Date()).getTime()) / 1000 / 60 / 60 / 24);
+  }
+
+  get goingToEvents(): Map<string, IEvent[]> {
+    const res = this.$data.loggedPerson.goingToEvents.filter((event) => {
+      return event.beginsOn != null && this.isBefore(event.beginsOn, 0)
+    });
+    res.sort(
+            (a: IEvent, b: IEvent) => new Date(a.beginsOn) > new Date(b.beginsOn),
+    );
+    const groups = res.reduce((acc: Map<string, IEvent[]>, event: IEvent) => {
+      const day = (new Date(event.beginsOn)).toDateString();
+      const events: IEvent[] = acc.get(day) || [];
+      events.push(event);
+      acc.set(day, events);
+      return acc;
+    }, new Map());
+    return groups;
   }
 
   geoLocalize() {
@@ -144,6 +224,6 @@ export default class Home extends Vue {
 }
 
 .events-nearby {
-  margin-bottom: 25px;
+  margin: 25px auto;
 }
 </style>
diff --git a/lib/mobilizon_web/resolvers/person.ex b/lib/mobilizon_web/resolvers/person.ex
index 43725edde..ce1814cbb 100644
--- a/lib/mobilizon_web/resolvers/person.ex
+++ b/lib/mobilizon_web/resolvers/person.ex
@@ -6,6 +6,7 @@ defmodule MobilizonWeb.Resolvers.Person do
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Users.User
   alias Mobilizon.Users
+  alias Mobilizon.Events
   alias Mobilizon.Service.ActivityPub
 
   @doc """
@@ -83,4 +84,34 @@ defmodule MobilizonWeb.Resolvers.Person do
         {:error, e}
     end
   end
+
+  @doc """
+  Returns the list of events this person is going to
+  """
+  def person_going_to_events(%Actor{id: actor_id}, _args, %{
+        context: %{current_user: user}
+      }) do
+    with {:is_owned, true, actor} <- User.owns_actor(user, actor_id),
+         events <- Events.list_event_participations_for_actor(actor) do
+      {:ok, events}
+    else
+      {:is_owned, false} ->
+        {:error, "Actor id is not owned by authenticated user"}
+    end
+  end
+
+  @doc """
+  Returns the list of events this person is going to
+  """
+  def person_going_to_events(_parent, %{}, %{
+        context: %{current_user: user}
+      }) do
+    with %Actor{} = actor <- Users.get_actor_for_user(user),
+         events <- Events.list_event_participations_for_actor(actor) do
+      {:ok, events}
+    else
+      {:is_owned, false} ->
+        {:error, "Actor id is not owned by authenticated user"}
+    end
+  end
 end
diff --git a/lib/mobilizon_web/schema/actors/person.ex b/lib/mobilizon_web/schema/actors/person.ex
index 8fe4c8ddf..c542009ac 100644
--- a/lib/mobilizon_web/schema/actors/person.ex
+++ b/lib/mobilizon_web/schema/actors/person.ex
@@ -53,6 +53,11 @@ defmodule MobilizonWeb.Schema.Actors.PersonType do
       resolve: dataloader(Events),
       description: "A list of the events this actor has organized"
     )
+
+    @desc "The list of events this person goes to"
+    field :going_to_events, list_of(:event) do
+      resolve(&Resolvers.Person.person_going_to_events/3)
+    end
   end
 
   object :person_queries do
diff --git a/lib/service/export/feed.ex b/lib/service/export/feed.ex
index ea5d89314..398e67408 100644
--- a/lib/service/export/feed.ex
+++ b/lib/service/export/feed.ex
@@ -88,7 +88,9 @@ defmodule Mobilizon.Service.Export.Feed do
   # Create an entry for the Atom feed
   @spec get_entry(Event.t()) :: any()
   defp get_entry(%Event{} = event) do
-    with {:ok, html, []} <- Earmark.as_html(event.description) do
+    description = event.description || ""
+
+    with {:ok, html, []} <- Earmark.as_html(description) do
       entry =
         Entry.new(event.url, event.publish_at || event.inserted_at, event.title)
         |> Entry.link(event.url, rel: "alternate", type: "text/html")
diff --git a/test/mobilizon_web/resolvers/person_resolver_test.exs b/test/mobilizon_web/resolvers/person_resolver_test.exs
index d5dbf64cc..698e05f72 100644
--- a/test/mobilizon_web/resolvers/person_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/person_resolver_test.exs
@@ -137,4 +137,86 @@ defmodule MobilizonWeb.Resolvers.PersonResolverTest do
                MapSet.new([actor.preferred_username, "new_identity"])
     end
   end
+
+  test "get_current_person/3 can return the events the person is going to", context do
+    user = insert(:user)
+    actor = insert(:actor, user: user)
+
+    query = """
+    {
+        loggedPerson {
+          goingToEvents {
+            uuid,
+            title
+          }
+        }
+      }
+    """
+
+    res =
+      context.conn
+      |> auth_conn(user)
+      |> get("/api", AbsintheHelpers.query_skeleton(query, "logged_person"))
+
+    assert json_response(res, 200)["data"]["loggedPerson"]["goingToEvents"] == []
+
+    event = insert(:event, %{organizer_actor: actor})
+    insert(:participant, %{actor: actor, event: event})
+
+    res =
+      context.conn
+      |> auth_conn(user)
+      |> get("/api", AbsintheHelpers.query_skeleton(query, "logged_person"))
+
+    assert json_response(res, 200)["data"]["loggedPerson"]["goingToEvents"] == [
+             %{"title" => event.title, "uuid" => event.uuid}
+           ]
+  end
+
+  test "find_person/3 can return the events an identity is going to if it's the same actor",
+       context do
+    user = insert(:user)
+    actor = insert(:actor, user: user)
+    insert(:actor, user: user)
+    actor_from_other_user = insert(:actor)
+
+    query = """
+    {
+      person(preferredUsername: "#{actor.preferred_username}") {
+          goingToEvents {
+            uuid,
+            title
+          }
+      }
+    }
+    """
+
+    res =
+      context.conn
+      |> auth_conn(user)
+      |> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
+
+    assert json_response(res, 200)["data"]["person"]["goingToEvents"] == []
+
+    query = """
+    {
+      person(preferredUsername: "#{actor_from_other_user.preferred_username}") {
+          goingToEvents {
+            uuid,
+            title
+          }
+      }
+    }
+    """
+
+    res =
+      context.conn
+      |> auth_conn(user)
+      |> get("/api", AbsintheHelpers.query_skeleton(query, "person"))
+
+    assert json_response(res, 200)["data"]["person"]["goingToEvents"] == nil
+
+    assert hd(json_response(res, 200)["errors"])["message"] ==
+             "Actor id is not owned by authenticated user"
+  end
 end