diff --git a/src/components/FetchSelf.js b/src/components/FetchSelf.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcfea4388fea5d096b1a1711bcfdff625f30cfd2
--- /dev/null
+++ b/src/components/FetchSelf.js
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { getSelf } from '../redux/actions/lookupApi';
+
+/**
+ * A component which causes the authenticated user's profile to be fetched from lookup when the
+ * user logs in and the profile has not previously been fetched. Since this list needs only to be
+ * fetched once, place it *outside* of any dynamic routes, etc.
+ *
+ * The fetching waits until auth.isLoggedIn becomes true.
+ */
+const FetchSelf = ({ isLoggedIn, self, selfLoading, getSelf }) => {
+
+  // If we are signed in and we haven't retrieved (and aren't retrieving) the profile -
+  // then retrieve the profile.
+  if (isLoggedIn && !self && !selfLoading) {
+    getSelf();
+  }
+
+  return null;
+};
+
+FetchSelf.propTypes = {
+  isLoggedIn: PropTypes.bool.isRequired,
+  self: PropTypes.object,
+  selfLoading: PropTypes.bool.isRequired,
+  getSelf: PropTypes.func.isRequired,
+};
+
+const mapStateToProps = ({ auth: { isLoggedIn }, lookupApi: { self, selfLoading } }) => ({
+  isLoggedIn, self, selfLoading
+});
+
+const mapDispatchToProps = { getSelf };
+
+export default connect(mapStateToProps, mapDispatchToProps)(FetchSelf);
diff --git a/src/components/FetchSelf.test.js b/src/components/FetchSelf.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a4d40723e35db95da04f8a6bac8491931e04d03
--- /dev/null
+++ b/src/components/FetchSelf.test.js
@@ -0,0 +1,31 @@
+import React from 'react';
+import {createMockStore, DEFAULT_INITIAL_STATE, render} from "../testutils";
+import { FetchSelf } from ".";
+import {PEOPLE_GET_SELF_REQUEST} from "../redux/actions/lookupApi";
+
+// Check that the profile is retrieved if we are logged in.
+test('The profile is retrieved if we are logged in', () => {
+  const store = createMockStore(DEFAULT_INITIAL_STATE);
+  const instance = render(<FetchSelf />, { store, url: '/' });
+  expect(store.getActions()).toEqual([{type: PEOPLE_GET_SELF_REQUEST}]);
+});
+
+// Check that the profile isn't retrieved if we are mid fetch.
+test("The profile isn't retrieved if we are mid fetch", () => {
+  const store = createMockStore({
+    ...DEFAULT_INITIAL_STATE,
+    lookupApi: {...DEFAULT_INITIAL_STATE.lookupApi, selfLoading: true}
+  });
+  const instance = render(<FetchSelf />, { store, url: '/' });
+  expect(store.getActions()).toEqual([]);
+});
+
+// Check that the profile isn't retrieved twice.
+test("The profile isn't retrieved twice", () => {
+  const store = createMockStore({
+    ...DEFAULT_INITIAL_STATE,
+    lookupApi: {...DEFAULT_INITIAL_STATE.lookupApi, self: {visibleName: "M. Bamford"}}
+  });
+  const instance = render(<FetchSelf />, { store, url: '/' });
+  expect(store.getActions()).toEqual([]);
+});
diff --git a/src/components/LogoutLink.js b/src/components/LogoutLink.js
index 66226da00038737e2777ac7dde65bed6b167087a..ee004fcb0d8f83fa8e6d313305baca88c4df8776 100644
--- a/src/components/LogoutLink.js
+++ b/src/components/LogoutLink.js
@@ -2,13 +2,14 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { logout } from '../redux/actions/auth';
+import { resetSelf } from "../redux/actions/lookupApi";
 
 /**
  * A link whose action will always log the current user out.
  */
-const LogoutLink = ({logout, children, ...rest}) => (
+const LogoutLink = ({logout, resetSelf, children, ...rest}) => (
   // eslint-disable-next-line
-  <a href="#" onClick={logout} {...rest}>{ children }</a>
+  <a href="#" onClick={() => {logout(); resetSelf()}} {...rest}>{ children }</a>
 );
 
 LogoutLink.propTypes = {
@@ -16,6 +17,6 @@ LogoutLink.propTypes = {
   logout: PropTypes.func.isRequired
 };
 
-const mapDispatchToProps = { logout };
+const mapDispatchToProps = { logout, resetSelf };
 
 export default connect(null, mapDispatchToProps)(LogoutLink);
diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index b9af8bd18a42822a32d1d4f903c08250fc4b8282..8ca0e868dea553d0d50fccc83b5c1b47f56b15d5 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -1,41 +1,54 @@
-import React from 'react';
+import React from 'react'
 import { withStyles } from 'material-ui/styles';
 
 import LogoutLink from './LogoutLink';
 import Divider from 'material-ui/Divider';
 import Toolbar from 'material-ui/Toolbar';
-import List from 'material-ui/List';
+import { List, ListItem } from 'material-ui';
 import SidebarNavLink from './SidebarNavLink';
 import Logo from '../images/cambridgeuniversity_logo.svg';
+import {connect} from "react-redux";
 
 const styles = theme => ({
   drawerHeader: theme.mixins.toolbar,
   nested: { paddingLeft: theme.spacing.unit * 4 },
   camLogo: { width: '145px', paddingTop: '10px'},
-  tagLine: { fontSize: 12},
-  logoToolbar: { flexDirection:'column', alignItems: 'flex-start', paddingLeft: theme.spacing.unit * 2  }
+  tagLine: { fontSize: 12 },
+  logoToolbar: { flexDirection:'column', alignItems: 'flex-start', paddingLeft: theme.spacing.unit * 2 },
+  assetHeading: { padding: '12px 16px' }
 });
 
 /**
  * The content of the IAR application side bar.
  */
-const Sidebar = ({ classes, history, logout }) => (
-  <div>
-    <div className={classes.drawerHeader}>
-      <Toolbar className={classes.logoToolbar} disableGutters={true}>
-        <img src={Logo} className={classes.camLogo} alt="Cambridge University Logo"/>
-        <div className={classes.tagLine}>Information Asset Register</div>
-      </Toolbar>
+const Sidebar = ({ classes, institutions, pathname }) => (
+    <div>
+      <div className={classes.drawerHeader}>
+        <Toolbar className={classes.logoToolbar} disableGutters={true}>
+          <img src={Logo} className={classes.camLogo} alt="Cambridge University Logo"/>
+          <div className={classes.tagLine}>Information Asset Register</div>
+        </Toolbar>
+      </div>
+      <Divider />
+
+      <List component='nav'>
+        <ListItem className={classes.assetHeading}>Assets:</ListItem>
+        {
+          /* TODO if you don't pass pathname here then "by department" Sidebar items don't re-render and item selection isn't updated */
+          institutions.map(({ instid, name }) => (
+            <SidebarNavLink key={instid} to={'/assets/' + instid} label={name} className={classes.nested} pathname={pathname} />
+          ))
+        }
+        {/* TODO if you don't pass pathname here then "by department" Sidebar items don't re-render and item selection isn't updated */}
+        <SidebarNavLink to='/assets' label='All departments' className={classes.nested} pathname={pathname} />
+        <SidebarNavLink to='/help' label='Help' />
+        <SidebarNavLink component={LogoutLink} label='Sign out' />
+      </List>
     </div>
-    <Divider />
+)
 
-    <List component='nav'>
-      <SidebarNavLink to='/assets/all' label='All Assets' />
-      <SidebarNavLink to='/assets/dept' label='Department of Foo' className={classes.nested} />
-      <SidebarNavLink to='/help' label='Help' />
-      <SidebarNavLink component={LogoutLink} label='Sign out' />
-    </List>
-  </div>
-);
+const mapStateToProps = ({ lookupApi: { self } }) => ({
+  institutions: self && self.institutions ? self.institutions : []
+});
 
-export default withStyles(styles)(Sidebar);
+export default connect(mapStateToProps)(withStyles(styles)(Sidebar));
diff --git a/src/components/Sidebar.test.js b/src/components/Sidebar.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7610be2c265ba224303c6747104ee25ed10adf59
--- /dev/null
+++ b/src/components/Sidebar.test.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import {createMockStore, DEFAULT_INITIAL_STATE, render} from "../testutils";
+import { Sidebar } from ".";
+import SidebarNavLink from "./SidebarNavLink";
+
+// Check that Sidebar items are rendered as expected.
+test('Sidebar items are rendered', () => {
+  const self = {
+    institutions: [
+      {instid: 'UIS', name: 'University Information Services'}
+    ]
+  };
+  const store = createMockStore({...DEFAULT_INITIAL_STATE, lookupApi: {self}});
+  const testInstance = render(<Sidebar />, { store, url: '/' });
+  const sidebarNavLinks = testInstance.findAllByType(SidebarNavLink);
+  expect(sidebarNavLinks).toHaveLength(4);
+  expect(sidebarNavLinks.find(link => link.props.label === 'University Information Services').props.to).toBe("/assets/UIS");
+  expect(sidebarNavLinks.find(link => link.props.label === 'All departments').props.to).toBe("/assets");
+  expect(sidebarNavLinks.find(link => link.props.label === 'Help').props.to).toBe("/help");
+  expect(sidebarNavLinks.find(link => link.props.label === 'Sign out')).not.toBeNull();
+});
diff --git a/src/components/index.js b/src/components/index.js
index 4d7ef6183387fa72f2f5e008e4ee89277c4a32bc..8cf95a153e91abbb54480caf1b49d5c427decd85 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,12 +1,23 @@
 import AssetFormHeader from './AssetFormHeader';
-import AssetListHeader from './AssetListHeader';
 import AssetListItem from './AssetListItem';
 import BooleanChoice from './BooleanChoice';
 import CheckboxGroup from './CheckboxGroup';
+import DeleteConfirmationDialog from './DeleteConfirmationDialog';
+import FetchSelf from './FetchSelf';
 import Lookup from './Lookup';
-import LoginButton from './LoginButton';
 import LoginRequiredRoute from './LoginRequiredRoute';
-import LogoutLink from './LogoutLink';
+import ScrollToTop from './ScrollToTop';
 import Sidebar from './Sidebar';
+import Snackbar from './Snackbar';
 
-export { AssetFormHeader, AssetListHeader, AssetListItem, BooleanChoice, CheckboxGroup, LoginButton, LoginRequiredRoute, LogoutLink, Lookup, Sidebar }
+export {
+  AssetFormHeader, AssetListItem,
+  BooleanChoice,
+  CheckboxGroup,
+  DeleteConfirmationDialog,
+  FetchSelf,
+  LoginRequiredRoute, Lookup,
+  ScrollToTop,
+  Sidebar,
+  Snackbar
+}
diff --git a/src/containers/App.js b/src/containers/App.js
index baddaf2a1442cc36e994acecda53c5fd5430102e..0997be7570184ace166f850a3700b8c4a6daa100 100644
--- a/src/containers/App.js
+++ b/src/containers/App.js
@@ -3,11 +3,9 @@ import { Provider as ReduxProvider } from 'react-redux';
 import { BrowserRouter as Router } from 'react-router-dom'
 import { MuiThemeProvider } from 'material-ui/styles';
 import { IntlProvider } from 'react-intl';
-import Snackbar from '../components/Snackbar';
+import { DeleteConfirmationDialog, FetchSelf, ScrollToTop, Snackbar } from '../components';
 import PropTypes from 'prop-types';
 import AppRoutes from './AppRoutes';
-import DeleteConfirmationDialog from '../components/DeleteConfirmationDialog';
-import ScrollToTop from '../components/ScrollToTop';
 import theme from '../style/CustomMaterialTheme';
 import '../style/App.css';
 
@@ -26,6 +24,7 @@ const App = ({ store }) => (
           </Router>
           <DeleteConfirmationDialog />
           <Snackbar />
+          <FetchSelf />
         </div>
       </ReduxProvider>
     </IntlProvider>
diff --git a/src/containers/AppRoutes.js b/src/containers/AppRoutes.js
index 889932e40af97a5c3ec0e56607b87a6655d36679..8d5265fbcbfbb3b9e033bb591d5aada9416d4925 100644
--- a/src/containers/AppRoutes.js
+++ b/src/containers/AppRoutes.js
@@ -14,13 +14,14 @@ import NotFoundPage from './NotFoundPage';
 const AppRoutes = () => (
   <Switch>
     <LoginRequiredRoute path="/assets/:filter" exact component={AssetList}/>
+    <LoginRequiredRoute path="/assets" exact component={AssetList}/>
     <LoginRequiredRoute path="/asset/:assetId" exact
                         component={routeProps => <AssetForm navigateOnSave='/' {...routeProps} />}
     />
     <LoginRequiredRoute path="/help" exact component={() => <Static page='help' />}/>
 
     <Route path="/oauth2-callback" exact component={() => <div />} />
-    <Redirect from='/' exact to='/assets/dept' />
+    <Redirect from='/' exact to='/assets' />
 
     { /* Catch all route for "not found" */ }
     <Route path="*" component={NotFoundPage} />
diff --git a/src/containers/AppRoutes.test.js b/src/containers/AppRoutes.test.js
index 851f9285e3f9372681263299f746335ddebcaaee..5981aabb79af543e5a6bff8e7fab7b47d94cc82e 100644
--- a/src/containers/AppRoutes.test.js
+++ b/src/containers/AppRoutes.test.js
@@ -21,22 +21,30 @@ test('can render /help', () => {
   expect(appBarTitle(testInstance)).toBe('Help')
 });
 
-test('can render /assets/dept', () => {
-  const testInstance = render(<AppRoutes/>, {url: '/assets/dept'});
+test('can render /assets/UIS', () => {
+  const self = {
+    institutions: [
+      {instid: 'UIS', name: 'University Information Services'}
+    ]
+  };
+  const testInstance = render(<AppRoutes/>, {
+    url: '/assets/UIS',
+    store: createMockStore({...DEFAULT_INITIAL_STATE, lookupApi: {self}})
+  });
 
-  expect(appBarTitle(testInstance)).toBe('Assets: My department')
+  expect(appBarTitle(testInstance)).toBe('Assets: University Information Services')
 });
 
 test('can render /assets/all', () => {
   const testInstance = render(<AppRoutes/>, {url: '/assets/all'});
 
-  expect(appBarTitle(testInstance)).toBe('Assets: All')
+  expect(appBarTitle(testInstance)).toBe('Assets: All departments')
 });
 
-test('/ redirects to /assets/dept', () => {
+test('/ redirects to /assets/all', () => {
   const testInstance = render(<AppRoutes/>, {url: '/'});
 
-  expect(appBarTitle(testInstance)).toBe('Assets: My department')
+  expect(appBarTitle(testInstance)).toBe('Assets: All departments')
 });
 
 test('can render /asset/create', () => {
diff --git a/src/containers/AssetForm.js b/src/containers/AssetForm.js
index c2438fedc80791e3dfdca6ab1b4e36355a0429ec..5431fedeed261dcfffa96ee60ec623d7d37b371c 100644
--- a/src/containers/AssetForm.js
+++ b/src/containers/AssetForm.js
@@ -419,7 +419,7 @@ AssetForm.propTypes = {
 
 const mapDispatchToProps = { snackbarOpen, getAsset, postAsset, putAsset };
 
-const mapStateToProps = ({ assets } , { match : {params: {assetId} } } ) => {
+const mapStateToProps = ({ assets }, { match : {params: {assetId} } } ) => {
 
   let assetUrl, asset = null;
 
diff --git a/src/containers/AssetForm.test.js b/src/containers/AssetForm.test.js
index cc434502a25bdf7f0146b093acbd45db4c7bf3c7..01119fb1c9468078bcc7e688977dcc257dd88755 100644
--- a/src/containers/AssetForm.test.js
+++ b/src/containers/AssetForm.test.js
@@ -12,6 +12,7 @@ import AssetForm from "./AssetForm";
 import {Route} from 'react-router-dom';
 import AssetFormHeader from '../components/AssetFormHeader';
 import {SNACKBAR_OPEN} from '../redux/actions/snackbar';
+import {PEOPLE_GET_SELF_REQUEST} from "../redux/actions/lookupApi";
 
 const NEW_ASSET_FIXTURE = {
   name: 'Super Secret Medical Data',
@@ -39,6 +40,7 @@ const ASSET_FIXTURE = {...NEW_ASSET_FIXTURE, url: ASSET_FIXTURE_URL};
 
 beforeEach(() => {
   fetch_mock.get(process.env.REACT_APP_ENDPOINT_LOOKUP + 'people/crsid/mb2174', {});
+  fetch_mock.get(process.env.REACT_APP_ENDPOINT_LOOKUP + 'people/token/self?fetch=all_insts', {});
   fetch_mock.get(process.env.REACT_APP_ENDPOINT_ASSETS + 'e20f4cd4-9f97-4829-8178-476c7a67eb97/', {});
 });
 
@@ -85,7 +87,9 @@ test('can populate a form with data', () => {
     url: '/asset/e20f4cd4-9f97-4829-8178-476c7a67eb97', store
   });
 
-  expect(store.getActions()).toEqual([{meta: {url: ASSET_FIXTURE_URL}, type: ASSET_GET_REQUEST}]);
+  expect(store.getActions()).toEqual([
+    {meta: {url: ASSET_FIXTURE_URL}, type: ASSET_GET_REQUEST}
+  ]);
 
   // test the ASSET_GET_REQUEST is dispatched
 
diff --git a/src/containers/AssetList.js b/src/containers/AssetList.js
index dc39d5344da0a97c834010917aeccb4c854f7cd7..4255c5a1aa822d1d4a3f44d8f39236457979c955 100644
--- a/src/containers/AssetList.js
+++ b/src/containers/AssetList.js
@@ -10,19 +10,15 @@ import { getAssets, Direction } from '../redux/actions/assetRegisterApi';
 
 import '../style/App.css';
 
-const TITLES = {
-  '/assets/dept': 'Assets: My department',
-  '/assets/all': 'Assets: All',
-};
-
 // Default query to use if none has previously been set by the user.
 export const DEFAULT_QUERY = {
   sort: { field: 'updated_at', direction: Direction.descending },
 };
 
 class AssetList extends Component {
+
   componentDidMount() {
-    const { getAssets, fetchedAt } = this.props;
+    const { fetchedAt } = this.props;
 
     // Fetch an asset list if one has not already been fetched. We detect an existing fetch by
     // looking at the "fetchedAt" value on the asset list which should be non-NULL if a fetch
@@ -30,21 +26,44 @@ class AssetList extends Component {
     if(!fetchedAt) {
       // If there is currently a sort query set by the user, use that otherwise update the query
       // with a default sort.
-      const { query } = this.props;
+      const { query, match : {params: {filter}} } = this.props;
       const { sort: { field } } = query;
       if(field !== null) {
-        getAssets(query);
+        this.getAssetsFilteredByDept(query, filter);
       } else {
-        getAssets({ ...query, ...DEFAULT_QUERY });
+        this.getAssetsFilteredByDept({ ...query, ...DEFAULT_QUERY }, filter);
       }
     }
   }
 
+  /**
+   * If the department filter has changed then re-fetch the list.
+   */
+  componentWillReceiveProps({match : {params: {filter: nextFilter}} }) {
+    const {match : {params: {filter}}, query} = this.props;
+    if (nextFilter !== filter) {
+      this.getAssetsFilteredByDept(query, nextFilter);
+    }
+  }
+
+  /**
+   * Method to apply or remove a department filter to a getAssets() call.
+   */
+  getAssetsFilteredByDept(query, filter = null) {
+    if (filter) {
+      query.filter = {...query.filter, department: filter}
+    } else {
+      delete query.filter.department
+    }
+
+    this.props.getAssets(query);
+  }
+
   render() {
-    const { match } = this.props;
+    const { institution } = this.props;
     return (
       <Page>
-        <AssetListHeader title={TITLES[match.url]} />
+        <AssetListHeader title={'Assets: ' + (institution ? institution.name : 'All departments')} />
 
         {/* Table of currently loaded assets. */}
         <AssetTable />
@@ -56,7 +75,7 @@ class AssetList extends Component {
       </Page>
     );
   }
-};
+}
 
 AssetList.propTypes = {
   match: PropTypes.object.isRequired,
@@ -64,9 +83,12 @@ AssetList.propTypes = {
   query: PropTypes.object.isRequired,
 };
 
-const mapStateToProps = ({ assets: { fetchedAt, query } }) => (
-  { fetchedAt, query }
-);
+const mapStateToProps = ({assets: {fetchedAt, query}, lookupApi: {self}}, {match : {params: {filter}}}) => {
+  // map the institution selected by the filter - if any.
+  const institutions = (self && self.institutions ? self.institutions : []);
+  const institution = institutions.find(institution => institution.instid === filter);
+  return { fetchedAt, query, institution };
+};
 
 const mapDispatchToProps = { getAssets };
 
diff --git a/src/containers/AssetList.test.js b/src/containers/AssetList.test.js
index a2ef0e7d986aa6d3999db427bac1c5ec33864b06..1eac6d846e65f604050ae4fc01b89545381d05aa 100644
--- a/src/containers/AssetList.test.js
+++ b/src/containers/AssetList.test.js
@@ -25,12 +25,12 @@ beforeEach(() => {
 // re-worked, we can move to testing the AssetList component directly.
 
 test('AssetList can render', () => {
-  const testInstance = render(<AppRoutes />, { url: '/assets/all' });
+  render(<AppRoutes />, { url: '/assets/all' });
 });
 
 test('AssetList sends a default query if none is set', () => {
   const store = createMockStore(DEFAULT_INITIAL_STATE);
-  const testInstance = render(<AppRoutes />, { store, url: '/assets/all' });
+  render(<AppRoutes />, { store, url: '/assets/all' });
 
   // getAssets was called once
   expect(getAssets.mock.calls).toHaveLength(1);
@@ -53,7 +53,7 @@ test('AssetList respects the current query', () => {
   initialState.assets = { ...initialState.assets, query: initialQuery };
 
   const store = createMockStore(initialState);
-  const testInstance = render(<AppRoutes />, { store, url: '/assets/all' });
+  render(<AppRoutes />, { store, url: '/assets/all' });
 
   // getAssets was called once
   expect(getAssets.mock.calls).toHaveLength(1);
@@ -66,3 +66,13 @@ test('AssetList respects the current query', () => {
     expect(query[name]).toEqual(initialQuery[name]);
   });
 });
+
+// check that a department filter is set
+test('A department filter is set', () => {
+  render(<AppRoutes />, { url: '/assets/UIS' });
+
+  expect(getAssets.mock.calls).toHaveLength(1);
+
+  const [ [ query ] ] = getAssets.mock.calls;
+  expect(query.filter.department).toEqual('UIS');
+});
diff --git a/src/containers/Page.js b/src/containers/Page.js
index 326790c32ed3a49595d58abc08cc1d43fecfd761..601be14cd8ca479ba9d86181d3f81e643a325059 100644
--- a/src/containers/Page.js
+++ b/src/containers/Page.js
@@ -5,6 +5,7 @@ import React from 'react';
 import { withStyles } from 'material-ui/styles';
 import { Sidebar } from '../components';
 import Drawer from 'material-ui/Drawer';
+import {withRouter} from "react-router-dom";
 
 const drawerWidth = 240;
 
@@ -26,10 +27,11 @@ const styles = theme => ({
   },
 });
 
-const Page = ({ children, classes }) => (
+const Page = ({ children, classes, location: {pathname} }) => (
   <div className={classes.appFrame}>
     <Drawer variant="permanent" classes={{paper: classes.drawerPaper}}>
-      <Sidebar />
+      {/* TODO if you don't pass pathname here then "by department" Sidebar items don't re-render and item selection isn't updated */}
+      <Sidebar pathname={pathname} />
     </Drawer>
     <div className={classes.pageContent}>
       { children }
@@ -37,4 +39,4 @@ const Page = ({ children, classes }) => (
   </div>
 );
 
-export default withStyles(styles)(Page);
+export default withRouter(withStyles(styles)(Page));
diff --git a/src/redux/actions/lookupApi.js b/src/redux/actions/lookupApi.js
index 1812277d5ed49bf93546b462bd7d78ab08e5e75f..29f23d71505f1dfde98c3bc669a2af373feb8d06 100644
--- a/src/redux/actions/lookupApi.js
+++ b/src/redux/actions/lookupApi.js
@@ -8,6 +8,11 @@ export const PEOPLE_GET_REQUEST = Symbol('PEOPLE_GET_REQUEST');
 export const PEOPLE_GET_SUCCESS = Symbol('PEOPLE_GET_SUCCESS');
 export const PEOPLE_GET_FAILURE = Symbol('PEOPLE_GET_FAILURE');
 
+export const PEOPLE_GET_SELF_REQUEST = Symbol('PEOPLE_GET_SELF_REQUEST');
+export const PEOPLE_GET_SELF_SUCCESS = Symbol('PEOPLE_GET_SELF_SUCCESS');
+export const PEOPLE_GET_SELF_FAILURE = Symbol('PEOPLE_GET_SELF_FAILURE');
+export const PEOPLE_GET_SELF_RESET = Symbol('PEOPLE_GET_SELF_RESET');
+
 export const ENDPOINT_PEOPLE = process.env.REACT_APP_ENDPOINT_LOOKUP + 'people';
 
 /**
@@ -44,3 +49,21 @@ export const getPeople = (crsid) => ({
     types: [PEOPLE_GET_REQUEST, PEOPLE_GET_SUCCESS, PEOPLE_GET_FAILURE]
   }
 });
+
+/**
+ * Fetch the authenticated user's profile.
+ */
+export const getSelf = () => ({
+  [RSAA]: {
+    endpoint: ENDPOINT_PEOPLE + '/token/self?fetch=all_insts',
+    method: 'GET',
+    types: [PEOPLE_GET_SELF_REQUEST, PEOPLE_GET_SELF_SUCCESS, PEOPLE_GET_SELF_FAILURE]
+  }
+});
+
+/**
+ * Reset the authenticated user's profile.
+ */
+export const resetSelf = () => ({
+  type: PEOPLE_GET_SELF_RESET,
+});
diff --git a/src/redux/reducers/lookupApi.js b/src/redux/reducers/lookupApi.js
index 710906b5f836d8f615997c387ab0fd5a421e1816..517397499b9f728f4ea52875824f09c70198c009 100644
--- a/src/redux/reducers/lookupApi.js
+++ b/src/redux/reducers/lookupApi.js
@@ -1,19 +1,26 @@
 import {
+  PEOPLE_GET_SELF_FAILURE,
+  PEOPLE_GET_SELF_REQUEST, PEOPLE_GET_SELF_RESET, PEOPLE_GET_SELF_SUCCESS,
   PEOPLE_GET_SUCCESS,
   PEOPLE_LIST_SUCCESS,
 } from '../actions/lookupApi';
 
 import Cache from '../cache';
+import { Map as ImmutableMap } from 'immutable';
 
 /**
  * State managed by the lookup API reducers.
  */
 export const initialState = {
   // a map of people records retrieved from the lookup api - keyed on crsid
-  peopleByCrsid: new Map(),
+  peopleByCrsid: ImmutableMap(),
   // a cache of arrays of people records returned by the lookup api search endpoint -
   // keyed on the search text that produced the result.
   matchingPeopleByQuery: new Cache({maxSize: 20}),
+  // the authenticated user's profile
+  self: null,
+  // whether or not the authenticated user's profile is being loaded
+  selfLoading: false,
 };
 
 export default (state = initialState, action) => {
@@ -27,11 +34,20 @@ export default (state = initialState, action) => {
     case PEOPLE_GET_SUCCESS:
       // Add the person to the peopleByCrsid map
       const person = action.payload;
-      const peopleByCrsid = new Map([
-        ...state.peopleByCrsid,
-        [person.identifier.value, person]
-      ]);
-      return { ...state, peopleByCrsid };
+      return { ...state, peopleByCrsid: state.peopleByCrsid.set(person.identifier.value, person) };
+
+    case PEOPLE_GET_SELF_REQUEST:
+      // use an empty object is indicate loading
+      return { ...state, selfLoading: true };
+
+    case PEOPLE_GET_SELF_RESET:
+    case PEOPLE_GET_SELF_FAILURE:
+      // reset self in case of reset and failure.
+      return { ...state, self: null, selfLoading: false };
+
+    case PEOPLE_GET_SELF_SUCCESS:
+      // Add the person to the peopleByCrsid map
+      return { ...state, self: action.payload, selfLoading: false};
 
     default:
       return state;
diff --git a/src/redux/reducers/lookupApi.test.js b/src/redux/reducers/lookupApi.test.js
index 4c6e726b3deb5ecde67d76102b9734de2ad816c4..62fa7aea04ee093b1cf5d1c1048a895edbe56f2b 100644
--- a/src/redux/reducers/lookupApi.test.js
+++ b/src/redux/reducers/lookupApi.test.js
@@ -1,6 +1,10 @@
 import Cache from '../cache';
+import { Map } from 'immutable';
 import reducer, { initialState } from './lookupApi';
-import { PEOPLE_GET_SUCCESS, PEOPLE_LIST_SUCCESS } from '../actions/lookupApi';
+import {
+  PEOPLE_GET_SELF_REQUEST, PEOPLE_GET_SELF_SUCCESS, PEOPLE_GET_SUCCESS,
+  PEOPLE_LIST_SUCCESS
+} from '../actions/lookupApi';
 
 // test that the state is correctly initialised.
 test('the state is correctly initialised', () => {
@@ -30,8 +34,9 @@ test('a people list result is cached', () => {
 
   const nextState = reducer(initialState, action);
 
-  expect(Object.is(initialState.matchingPeopleByQuery, nextState.matchingPeopleByQuery)).toBe(false);
   expect(nextState.matchingPeopleByQuery.get('msb9')).toBe(results);
+  // check the state wasn't mutated
+  expect(Object.is(initialState.matchingPeopleByQuery, nextState.matchingPeopleByQuery)).toBe(false);
 });
 
 // test the people list cache doesn't grow beyond 20
@@ -61,7 +66,7 @@ test('the people list cache is pruned', () => {
   expect(nextState.matchingPeopleByQuery.get('msb10')).toBeDefined();
 });
 
-// a retrieved person model is set in peopleByCrsid
+// check that a retrieved person model is set in peopleByCrsid
 test('a retrieved person model is set in peopleByCrsid', () => {
 
   const payload = {
@@ -75,6 +80,40 @@ test('a retrieved person model is set in peopleByCrsid', () => {
 
   const nextState = reducer(initialState, {type: PEOPLE_GET_SUCCESS, payload: payload});
 
-  expect(Object.is(initialState.peopleByCrsid, nextState.peopleByCrsid)).toBe(false);
   expect(nextState.peopleByCrsid.get('msb999')).toBe(payload);
+  // check the state wasn't mutated
+  expect(Object.is(initialState.peopleByCrsid, nextState.peopleByCrsid)).toBe(false);
+});
+
+// check that the selfLoading flag is set when the self is requested
+test("the selfLoading flag is set", () => {
+
+  const nextState = reducer(initialState, {type: PEOPLE_GET_SELF_REQUEST});
+
+  expect(nextState.self).toBeNull();
+  expect(nextState.selfLoading).toBe(true);
+});
+
+// check that the authenticated user's profile is set in self
+test("the authenticated user's profile is set in self", () => {
+
+  const payload = {
+    url: "http://localhost:8080/people/crsid/msb999",
+    cancelled: false,
+    identifier: {scheme: "crsid", value: "msb999"},
+    visibleName: "M. Bamford",
+    isStaff: true,
+    isStudent: false,
+    institutions:[
+      {instid:"CL",name:"Department of Computer Science and Technology"},
+      {instid:"UIS",name:"University Information Services"}
+    ]
+  };
+
+  const nextState = reducer(initialState, {type: PEOPLE_GET_SELF_SUCCESS, payload: payload});
+
+  expect(nextState.self).toBe(payload);
+  expect(nextState.selfLoading).toBe(false);
+  // check the state wasn't mutated
+  expect(Object.is(initialState.self, nextState.self)).toBe(false);
 });