Initially working on flatbuffers backend
diff --git a/FbsKerbydata.mon b/FbsKerbydata.mon
new file mode 100644
index 0000000..355dd76
--- /dev/null
+++ b/FbsKerbydata.mon
Binary files differ
diff --git a/kerby-backend/flatbuffers-backend/CodeGen.sh b/kerby-backend/flatbuffers-backend/CodeGen.sh
new file mode 100644
index 0000000..aa4ece6
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/CodeGen.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# To be refined, considering license headers, formats and etc.
+flatc -j --gen-mutable -o src/main/java src/schema/kerby.fbs
\ No newline at end of file
diff --git a/kerby-backend/flatbuffers-backend/pom.xml b/kerby-backend/flatbuffers-backend/pom.xml
new file mode 100644
index 0000000..772a831
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.kerby</groupId>
+    <artifactId>kerby-backend</artifactId>
+    <version>1.0.0-RC2-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>flatbuffers-backend</artifactId>
+
+  <name>Flatbuffers identity backend</name>
+  <description>Flatbuffers identity backend</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerby-config</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-identity</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-identity-test</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.3.1</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Constants.java b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Constants.java
new file mode 100644
index 0000000..67585d7
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Constants.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+// Class that holds shared constants.
+
+public class Constants {
+    // Java doesn't seem to have these.
+    static final int SIZEOF_SHORT = 2;
+    static final int SIZEOF_INT = 4;
+    static final int FILE_IDENTIFIER_LENGTH = 4;
+}
+
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java
new file mode 100644
index 0000000..368be2f
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -0,0 +1,523 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import static com.google.flatbuffers.Constants.*;
+import java.util.Arrays;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * Class that helps you build a FlatBuffer.  See the section
+ * <a href="http://google.github.io/flatbuffers/md__java_usage.html">"Use in Java"</a> in the
+ * main FlatBuffers documentation.
+ */
+public class FlatBufferBuilder {
+    ByteBuffer bb;          // Where we construct the FlatBuffer.
+    int space;              // Remaining space in the ByteBuffer.
+    static final Charset utf8charset = Charset.forName("UTF-8");
+    int minalign = 1;       // Minimum alignment encountered so far.
+    int[] vtable = null;    // The vtable for the current table.
+    int vtable_in_use = 0;  // The amount of fields we're actually using.
+    boolean nested = false; // Whether we are currently serializing a table.
+    int object_start;       // Starting offset of the current struct/table.
+    int[] vtables = new int[16];  // List of offsets of all vtables.
+    int num_vtables = 0;          // Number of entries in `vtables` in use.
+    int vector_num_elems = 0;     // For the current vector being built.
+    boolean force_defaults = false; // False omits default values from the serialized data
+
+   /**
+    * Start with a buffer of size {@code initial_size}, then grow as required.
+    *
+    * @param initial_size The initial size of the internal buffer to use
+    */
+    public FlatBufferBuilder(int initial_size) {
+        if (initial_size <= 0) initial_size = 1;
+        space = initial_size;
+        bb = newByteBuffer(initial_size);
+    }
+
+   /**
+    * Start with a buffer of 1KiB, then grow as required.
+    */
+    public FlatBufferBuilder() {
+        this(1024);
+    }
+
+    /**
+     * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
+     * can still grow the buffer as necessary.  User classes should make sure
+     * to call {@link #dataBuffer()} to obtain the resulting encoded message
+     *
+     * @param existing_bb The byte buffer to reuse
+     */
+    public FlatBufferBuilder(ByteBuffer existing_bb) {
+        init(existing_bb);
+    }
+
+    /**
+     * Alternative initializer that allows reusing this object on an existing
+     * ByteBuffer. This method resets the builder's internal state, but keeps
+     * objects that have been allocated for temporary storage.
+     *
+     * @param existing_bb The byte buffer to reuse
+     * @return this
+     */
+    public FlatBufferBuilder init(ByteBuffer existing_bb){
+        bb = existing_bb;
+        bb.clear();
+        bb.order(ByteOrder.LITTLE_ENDIAN);
+        minalign = 1;
+        space = bb.capacity();
+        vtable_in_use = 0;
+        nested = false;
+        object_start = 0;
+        num_vtables = 0;
+        vector_num_elems = 0;
+        return this;
+    }
+
+    static ByteBuffer newByteBuffer(int capacity) {
+        ByteBuffer newbb = ByteBuffer.allocate(capacity);
+        newbb.order(ByteOrder.LITTLE_ENDIAN);
+        return newbb;
+    }
+
+    /**
+     * Doubles the size of the backing {link ByteBuffer} and copies the old data towards the
+     * end of the new buffer (since we build the buffer backwards).
+     *
+     * @param bb The current buffer with the existing data
+     * @return A new byte buffer with the old data copied copied to it.  The data is
+     * located at the end of the buffer.
+     */
+    static ByteBuffer growByteBuffer(ByteBuffer bb) {
+        int old_buf_size = bb.capacity();
+        if ((old_buf_size & 0xC0000000) != 0)  // Ensure we don't grow beyond what fits in an int.
+            throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
+        int new_buf_size = old_buf_size << 1;
+        bb.position(0);
+        ByteBuffer nbb = newByteBuffer(new_buf_size);
+        nbb.position(new_buf_size - old_buf_size);
+        nbb.put(bb);
+        return nbb;
+    }
+
+   /**
+    * Offset relative to the end of the buffer.
+    *
+    * @return Offset relative to the end of the buffer.
+    */
+    public int offset() {
+        return bb.capacity() - space;
+    }
+
+   /**
+    * Add zero valued bytes to prepare a new entry to be added
+    *
+    * @param byte_size Number of bytes to add.
+    */
+    public void pad(int byte_size) {
+        for (int i = 0; i < byte_size; i++) bb.put(--space, (byte)0);
+    }
+
+   /**
+    * Prepare to write an element of {@code size} after {@code additional_bytes}
+    * have been written, e.g. if you write a string, you need to align such
+    * the int length field is aligned to {@link com.google.flatbuffers.Constants#SIZEOF_INT}, and
+    * the string data follows it directly.  If all you need to do is alignment, {@code additional_bytes}
+    * will be 0.
+    *
+    * @param size This is the of the new element to write
+    * @param additional_bytes The padding size
+    */
+    public void prep(int size, int additional_bytes) {
+        // Track the biggest thing we've ever aligned to.
+        if (size > minalign) minalign = size;
+        // Find the amount of alignment needed such that `size` is properly
+        // aligned after `additional_bytes`
+        int align_size = ((~(bb.capacity() - space + additional_bytes)) + 1) & (size - 1);
+        // Reallocate the buffer if needed.
+        while (space < align_size + size + additional_bytes) {
+            int old_buf_size = bb.capacity();
+            bb = growByteBuffer(bb);
+            space += bb.capacity() - old_buf_size;
+        }
+        pad(align_size);
+    }
+
+    // Add a scalar to the buffer, backwards from the current location.
+    // Doesn't align nor check for space.
+    public void putBoolean(boolean x) { bb.put      (space -= 1, (byte)(x ? 1 : 0)); }
+    public void putByte   (byte    x) { bb.put      (space -= 1, x); }
+    public void putShort  (short   x) { bb.putShort (space -= 2, x); }
+    public void putInt    (int     x) { bb.putInt   (space -= 4, x); }
+    public void putLong   (long    x) { bb.putLong  (space -= 8, x); }
+    public void putFloat  (float   x) { bb.putFloat (space -= 4, x); }
+    public void putDouble (double  x) { bb.putDouble(space -= 8, x); }
+
+    // Adds a scalar to the buffer, properly aligned, and the buffer grown
+    // if needed.
+    public void addBoolean(boolean x) { prep(1, 0); putBoolean(x); }
+    public void addByte   (byte    x) { prep(1, 0); putByte   (x); }
+    public void addShort  (short   x) { prep(2, 0); putShort  (x); }
+    public void addInt    (int     x) { prep(4, 0); putInt    (x); }
+    public void addLong   (long    x) { prep(8, 0); putLong   (x); }
+    public void addFloat  (float   x) { prep(4, 0); putFloat  (x); }
+    public void addDouble (double  x) { prep(8, 0); putDouble (x); }
+
+   /**
+    * Adds on offset, relative to where it will be written.
+    *
+    * @param off The offset to add
+    */
+    public void addOffset(int off) {
+        prep(SIZEOF_INT, 0);  // Ensure alignment is already done.
+        assert off <= offset();
+        off = offset() - off + SIZEOF_INT;
+        putInt(off);
+    }
+
+   /**
+    * Start a new array/vector of objects.  Users usually will not call
+    * this directly.  The {@code FlatBuffers} compiler will create a start/end
+    * method for vector types in generated code.
+    * <p>
+    * The expected sequence of calls is:
+    * <ol>
+    * <li>Start the array using this method.</li>
+    * <li>Call {@link #addOffset(int)} {@code num_elems} number of times to set
+    * the offset of each element in the array.</li>
+    * <li>Call {@link #endVector()} to retrieve the offset of the array.</li>
+    * </ol>
+    * <p>
+    * For example, to create an array of strings, do:
+    * <pre>{@code
+    * // Need 10 strings
+    * FlatBufferBuilder builder = new FlatBufferBuilder(existingBuffer);
+    * int[] offsets = new int[10];
+    *
+    * for (int i = 0; i < 10; i++) {
+    *   offsets[i] = fbb.createString(" " + i);
+    * }
+    *
+    * // Have the strings in the buffer, but don't have a vector.
+    * // Add a vector that references the newly created strings:
+    * builder.startVector(4, offsets.length, 4);
+    *
+    * // Add each string to the newly created vector
+    * // The strings are added in reverse order since the buffer
+    * // is filled in back to front
+    * for (int i = offsets.length - 1; i >= 0; i--) {
+    *   builder.addOffset(offsets[i]);
+    * }
+    *
+    * // Finish off the vector
+    * int offsetOfTheVector = fbb.endVector();
+    * }</pre>
+    *
+    * @param elem_size The size of each element in the array
+    * @param num_elems The number of elements in the array
+    * @param alignment The alignment of the array
+    */
+    public void startVector(int elem_size, int num_elems, int alignment) {
+        notNested();
+        vector_num_elems = num_elems;
+        prep(SIZEOF_INT, elem_size * num_elems);
+        prep(alignment, elem_size * num_elems); // Just in case alignment > int.
+    }
+
+   /**
+    * Finish off the creation of an array and all its elements.  The array
+    * must be created with {@link #startVector(int, int, int)}.
+    *
+    * @return The offset at which the newly created array starts.
+    * @see #startVector(int, int, int)
+    */
+    public int endVector() {
+        putInt(vector_num_elems);
+        return offset();
+    }
+
+   /**
+    * Encode the string {@code s} in the buffer using UTF-8.
+    *
+    * @param s The string to encode
+    * @return The offset in the buffer where the encoded string starts
+    */
+    public int createString(String s) {
+        byte[] utf8 = s.getBytes(utf8charset);
+        addByte((byte)0);
+        startVector(1, utf8.length, 1);
+        bb.position(space -= utf8.length);
+        bb.put(utf8, 0, utf8.length);
+        return endVector();
+    }
+
+   /**
+    * Encode the string {@code s} in the buffer using UTF-8.
+    *
+    * @param s An already encoded UTF-8 string
+    * @return The offset in the buffer where the encoded string starts
+    */
+    public int createString(ByteBuffer s) {
+        int length = s.remaining();
+        addByte((byte)0);
+        startVector(1, length, 1);
+        bb.position(space -= length);
+        bb.put(s);
+        return endVector();
+    }
+
+   /**
+    * Should not be creating any other object, string or vector
+    * while an object is being constructed
+    */
+    public void notNested() {
+        if (nested)
+            throw new AssertionError("FlatBuffers: object serialization must not be nested.");
+    }
+
+   /**
+    * Structures are always stored inline, they need to be created right
+    * where they're used.  You'll get this assertion failure if you
+    * created it elsewhere.
+    *
+    * @param obj The offset of the created object
+    */
+    public void Nested(int obj) {
+        if (obj != offset())
+            throw new AssertionError("FlatBuffers: struct must be serialized inline.");
+    }
+
+   /**
+    * Start encoding a new object in the buffer.  Users will not usually need to
+    * call this directly. The {@code FlatBuffers} compiler will generate helper methods
+    * that call this method internally.
+    * <p>
+    * For example, using the "Monster" code found on the
+    * <a href="http://google.github.io/flatbuffers/md__java_usage.html">landing page</a>. An
+    * object of type {@code Monster} can be created using the following code:
+    *
+    * <pre>{@code
+    * int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
+    *   fbb.createString("test1"),
+    *   fbb.createString("test2")
+    * });
+    *
+    * Monster.startMonster(fbb);
+    * Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+    *   Color.Green, (short)5, (byte)6));
+    * Monster.addHp(fbb, (short)80);
+    * Monster.addName(fbb, str);
+    * Monster.addInventory(fbb, inv);
+    * Monster.addTestType(fbb, (byte)Any.Monster);
+    * Monster.addTest(fbb, mon2);
+    * Monster.addTest4(fbb, test4);
+    * Monster.addTestarrayofstring(fbb, testArrayOfString);
+    * int mon = Monster.endMonster(fbb);
+    * }</pre>
+    * <p>
+    * Here:
+    * <ul>
+    * <li>The call to {@code Monster#startMonster(FlatBufferBuilder)} will call this
+    * method with the right number of fields set.</li>
+    * <li>{@code Monster#endMonster(FlatBufferBuilder)} will ensure {@link #endObject()} is called.</li>
+    * </ul>
+    * <p>
+    * It's not recommended to call this method directly.  If it's called manually, you must ensure
+    * to audit all calls to it whenever fields are added or removed from your schema.  This is
+    * automatically done by the code generated by the {@code FlatBuffers} compiler.
+    *
+    * @param numfields The number of fields found in this object.
+    */
+    public void startObject(int numfields) {
+        notNested();
+        if (vtable == null || vtable.length < numfields) vtable = new int[numfields];
+        vtable_in_use = numfields;
+        Arrays.fill(vtable, 0, vtable_in_use, 0);
+        nested = true;
+        object_start = offset();
+    }
+
+    // Add a scalar to a table at `o` into its vtable, with value `x` and default `d`
+    public void addBoolean(int o, boolean x, boolean d) { if(force_defaults || x != d) { addBoolean(x); slot(o); } }
+    public void addByte   (int o, byte    x, int     d) { if(force_defaults || x != d) { addByte   (x); slot(o); } }
+    public void addShort  (int o, short   x, int     d) { if(force_defaults || x != d) { addShort  (x); slot(o); } }
+    public void addInt    (int o, int     x, int     d) { if(force_defaults || x != d) { addInt    (x); slot(o); } }
+    public void addLong   (int o, long    x, long    d) { if(force_defaults || x != d) { addLong   (x); slot(o); } }
+    public void addFloat  (int o, float   x, double  d) { if(force_defaults || x != d) { addFloat  (x); slot(o); } }
+    public void addDouble (int o, double  x, double  d) { if(force_defaults || x != d) { addDouble (x); slot(o); } }
+    public void addOffset (int o, int     x, int     d) { if(force_defaults || x != d) { addOffset (x); slot(o); } }
+
+    // Structs are stored inline, so nothing additional is being added. `d` is always 0.
+    public void addStruct(int voffset, int x, int d) {
+        if(x != d) {
+            Nested(x);
+            slot(voffset);
+        }
+    }
+
+    // Set the current vtable at `voffset` to the current location in the buffer.
+    public void slot(int voffset) {
+        vtable[voffset] = offset();
+    }
+
+   /**
+    * Finish off writing the object that is under construction.
+    *
+    * @return The offset to the object inside {@link #dataBuffer()}
+    * @see #startObject(int)
+    */
+    public int endObject() {
+        if (vtable == null || !nested)
+            throw new AssertionError("FlatBuffers: endObject called without startObject");
+        addInt(0);
+        int vtableloc = offset();
+        // Write out the current vtable.
+        for (int i = vtable_in_use - 1; i >= 0 ; i--) {
+            // Offset relative to the start of the table.
+            short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
+            addShort(off);
+        }
+
+        final int standard_fields = 2; // The fields below:
+        addShort((short)(vtableloc - object_start));
+        addShort((short)((vtable_in_use + standard_fields) * SIZEOF_SHORT));
+
+        // Search for an existing vtable that matches the current one.
+        int existing_vtable = 0;
+        outer_loop:
+        for (int i = 0; i < num_vtables; i++) {
+            int vt1 = bb.capacity() - vtables[i];
+            int vt2 = space;
+            short len = bb.getShort(vt1);
+            if (len == bb.getShort(vt2)) {
+                for (int j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) {
+                    if (bb.getShort(vt1 + j) != bb.getShort(vt2 + j)) {
+                        continue outer_loop;
+                    }
+                }
+                existing_vtable = vtables[i];
+                break outer_loop;
+            }
+        }
+
+        if (existing_vtable != 0) {
+            // Found a match:
+            // Remove the current vtable.
+            space = bb.capacity() - vtableloc;
+            // Point table to existing vtable.
+            bb.putInt(space, existing_vtable - vtableloc);
+        } else {
+            // No match:
+            // Add the location of the current vtable to the list of vtables.
+            if (num_vtables == vtables.length) vtables = Arrays.copyOf(vtables, num_vtables * 2);
+            vtables[num_vtables++] = offset();
+            // Point table to current vtable.
+            bb.putInt(bb.capacity() - vtableloc, offset() - vtableloc);
+        }
+
+        nested = false;
+        return vtableloc;
+    }
+
+    // This checks a required field has been set in a given table that has
+    // just been constructed.
+    public void required(int table, int field) {
+        int table_start = bb.capacity() - table;
+        int vtable_start = table_start - bb.getInt(table_start);
+        boolean ok = bb.getShort(vtable_start + field) != 0;
+        // If this fails, the caller will show what field needs to be set.
+        if (!ok)
+            throw new AssertionError("FlatBuffers: field " + field + " must be set");
+    }
+
+    public void finish(int root_table) {
+        prep(minalign, SIZEOF_INT);
+        addOffset(root_table);
+        bb.position(space);
+    }
+
+    public void finish(int root_table, String file_identifier) {
+        prep(minalign, SIZEOF_INT + FILE_IDENTIFIER_LENGTH);
+        if (file_identifier.length() != FILE_IDENTIFIER_LENGTH)
+            throw new AssertionError("FlatBuffers: file identifier must be length " +
+                                     FILE_IDENTIFIER_LENGTH);
+        for (int i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
+            addByte((byte)file_identifier.charAt(i));
+        }
+        finish(root_table);
+    }
+
+    /**
+     * In order to save space, fields that are set to their default value
+     * don't get serialized into the buffer. Forcing defaults provides a
+     * way to manually disable this optimization.
+     *
+     * @param forceDefaults true always serializes default values
+     * @return this
+     */
+    public FlatBufferBuilder forceDefaults(boolean forceDefaults){
+        this.force_defaults = forceDefaults;
+        return this;
+    }
+
+    // Get the ByteBuffer representing the FlatBuffer. Only call this after you've
+    // called finish(). The actual data starts at the ByteBuffer's current position,
+    // not necessarily at 0.
+    public ByteBuffer dataBuffer() { return bb; }
+
+   /**
+    * The FlatBuffer data doesn't start at offset 0 in the {@link ByteBuffer}, but
+    * now the {@code ByteBuffer}'s position is set to that location upon {@link #finish(int)}.
+    *
+    * @return The {@link ByteBuffer#position() position} the data starts in {@link #dataBuffer()}
+    * @deprecated This method should not be needed anymore, but is left
+    * here for the moment to document this API change. It will be removed in the future.
+    */
+    @Deprecated
+    private int dataStart() {
+        return space;
+    }
+
+   /**
+    * Utility function for copying a byte array from {@code start} to
+    * {@code start} + {@code length}
+    *
+    * @param start Start copying at this offset
+    * @param length How many bytes to copy
+    * @return A range copy of the {@link #dataBuffer() data buffer}
+    * @throws IndexOutOfBoundsException If the range of bytes is ouf of bound
+    */
+    public byte[] sizedByteArray(int start, int length){
+        byte[] array = new byte[length];
+        bb.position(start);
+        bb.get(array);
+        return array;
+    }
+
+   /**
+    * Utility function for copying a byte array that starts at 0.
+    *
+    * @return A full copy of the {@link #dataBuffer() data buffer}
+    */
+    public byte[] sizedByteArray() {
+        return sizedByteArray(space, bb.capacity() - space);
+    }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Struct.java b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Struct.java
new file mode 100644
index 0000000..9e6fe4a
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Struct.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import java.nio.ByteBuffer;
+
+// All structs in the generated code derive from this class, and add their own accessors.
+public class Struct {
+  protected int bb_pos;
+  protected ByteBuffer bb;
+}
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Table.java b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Table.java
new file mode 100644
index 0000000..c4a9375
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/com/google/flatbuffers/Table.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.flatbuffers;
+
+import static com.google.flatbuffers.Constants.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+// All tables in the generated code derive from this class, and add their own accessors.
+public class Table {
+  protected int bb_pos;
+  protected ByteBuffer bb;
+
+  public ByteBuffer getByteBuffer() { return bb; }
+
+  // Look up a field in the vtable, return an offset into the object, or 0 if the field is not
+  // present.
+  protected int __offset(int vtable_offset) {
+    int vtable = bb_pos - bb.getInt(bb_pos);
+    return vtable_offset < bb.getShort(vtable) ? bb.getShort(vtable + vtable_offset) : 0;
+  }
+
+  // Retrieve the relative offset stored at "offset"
+  protected int __indirect(int offset) {
+    return offset + bb.getInt(offset);
+  }
+
+  // Create a java String from UTF-8 data stored inside the flatbuffer.
+  // This allocates a new string and converts to wide chars upon each access,
+  // which is not very efficient. Instead, each FlatBuffer string also comes with an
+  // accessor based on __vector_as_bytebuffer below, which is much more efficient,
+  // assuming your Java program can handle UTF-8 data directly.
+  protected String __string(int offset) {
+    offset += bb.getInt(offset);
+    if (bb.hasArray()) {
+      return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset), FlatBufferBuilder.utf8charset);
+    } else {
+      // We can't access .array(), since the ByteBuffer is read-only,
+      // off-heap or a memory map
+      ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+      // We're forced to make an extra copy:
+      byte[] copy = new byte[bb.getInt(offset)];
+      bb.position(offset + SIZEOF_INT);
+      bb.get(copy);
+      return new String(copy, 0, copy.length, FlatBufferBuilder.utf8charset);
+    }
+  }
+
+  // Get the length of a vector whose offset is stored at "offset" in this object.
+  protected int __vector_len(int offset) {
+    offset += bb_pos;
+    offset += bb.getInt(offset);
+    return bb.getInt(offset);
+  }
+
+  // Get the start of data of a vector whose offset is stored at "offset" in this object.
+  protected int __vector(int offset) {
+    offset += bb_pos;
+    return offset + bb.getInt(offset) + SIZEOF_INT;  // data starts after the length
+  }
+
+  // Get a whole vector as a ByteBuffer. This is efficient, since it only allocates a new
+  // bytebuffer object, but does not actually copy the data, it still refers to the same
+  // bytes as the original ByteBuffer.
+  // Also useful with nested FlatBuffers etc.
+  protected ByteBuffer __vector_as_bytebuffer(int vector_offset, int elem_size) {
+    int o = __offset(vector_offset);
+    if (o == 0) return null;
+    ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
+    int vectorstart = __vector(o);
+    bb.position(vectorstart);
+    bb.limit(vectorstart + __vector_len(o) * elem_size);
+    return bb;
+  }
+
+  // Initialize any Table-derived type to point to the union at the given offset.
+  protected Table __union(Table t, int offset) {
+    offset += bb_pos;
+    t.bb_pos = offset + bb.getInt(offset);
+    t.bb = bb;
+    return t;
+  }
+
+  protected static boolean __has_identifier(ByteBuffer bb, String ident) {
+    if (ident.length() != FILE_IDENTIFIER_LENGTH)
+        throw new AssertionError("FlatBuffers: file identifier must be length " +
+                                 FILE_IDENTIFIER_LENGTH);
+    for (int i = 0; i < FILE_IDENTIFIER_LENGTH; i++) {
+      if (ident.charAt(i) != (char)bb.get(bb.position() + SIZEOF_INT + i)) return false;
+    }
+    return true;
+  }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsEncryptionKey.java b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsEncryptionKey.java
new file mode 100644
index 0000000..3600666
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsEncryptionKey.java
@@ -0,0 +1,42 @@
+// automatically generated, do not modify
+
+package org.apache.kerby.kerberos.kdc.identitybackend;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class FbsEncryptionKey extends Table {
+  public static FbsEncryptionKey getRootAsFbsEncryptionKey(ByteBuffer _bb) { return getRootAsFbsEncryptionKey(_bb, new FbsEncryptionKey()); }
+  public static FbsEncryptionKey getRootAsFbsEncryptionKey(ByteBuffer _bb, FbsEncryptionKey obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public FbsEncryptionKey __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public int keyType() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateKeyType(int keyType) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, keyType); return true; } else { return false; } }
+  public byte keyValue(int j) { int o = __offset(6); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+  public int keyValueLength() { int o = __offset(6); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer keyValueAsByteBuffer() { return __vector_as_bytebuffer(6, 1); }
+  public boolean mutateKeyValue(int j, byte keyValue) { int o = __offset(6); if (o != 0) { bb.put(__vector(o) + j * 1, keyValue); return true; } else { return false; } }
+
+  public static int createFbsEncryptionKey(FlatBufferBuilder builder,
+      int keyType,
+      int keyValue) {
+    builder.startObject(2);
+    FbsEncryptionKey.addKeyValue(builder, keyValue);
+    FbsEncryptionKey.addKeyType(builder, keyType);
+    return FbsEncryptionKey.endFbsEncryptionKey(builder);
+  }
+
+  public static void startFbsEncryptionKey(FlatBufferBuilder builder) { builder.startObject(2); }
+  public static void addKeyType(FlatBufferBuilder builder, int keyType) { builder.addInt(0, keyType, 0); }
+  public static void addKeyValue(FlatBufferBuilder builder, int keyValueOffset) { builder.addOffset(1, keyValueOffset, 0); }
+  public static int createKeyValueVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+  public static void startKeyValueVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static int endFbsEncryptionKey(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKerby.java b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKerby.java
new file mode 100644
index 0000000..21f8363
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKerby.java
@@ -0,0 +1,42 @@
+// automatically generated, do not modify
+
+package org.apache.kerby.kerberos.kdc.identitybackend;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class FbsKerby extends Table {
+  public static FbsKerby getRootAsFbsKerby(ByteBuffer _bb) { return getRootAsFbsKerby(_bb, new FbsKerby()); }
+  public static FbsKerby getRootAsFbsKerby(ByteBuffer _bb, FbsKerby obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public FbsKerby __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public String name() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
+  public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
+  public FbsKrbIdentity identities(int j) { return identities(new FbsKrbIdentity(), j); }
+  public FbsKrbIdentity identities(FbsKrbIdentity obj, int j) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
+  public int identitiesLength() { int o = __offset(6); return o != 0 ? __vector_len(o) : 0; }
+
+  public static int createFbsKerby(FlatBufferBuilder builder,
+      int name,
+      int identities) {
+    builder.startObject(2);
+    FbsKerby.addIdentities(builder, identities);
+    FbsKerby.addName(builder, name);
+    return FbsKerby.endFbsKerby(builder);
+  }
+
+  public static void startFbsKerby(FlatBufferBuilder builder) { builder.startObject(2); }
+  public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(0, nameOffset, 0); }
+  public static void addIdentities(FlatBufferBuilder builder, int identitiesOffset) { builder.addOffset(1, identitiesOffset, 0); }
+  public static int createIdentitiesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+  public static void startIdentitiesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+  public static int endFbsKerby(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+  public static void finishFbsKerbyBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset); }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKrbIdentity.java b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKrbIdentity.java
new file mode 100644
index 0000000..13a1314
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsKrbIdentity.java
@@ -0,0 +1,56 @@
+// automatically generated, do not modify
+
+package org.apache.kerby.kerberos.kdc.identitybackend;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class FbsKrbIdentity extends Table {
+  public static FbsKrbIdentity getRootAsFbsKrbIdentity(ByteBuffer _bb) { return getRootAsFbsKrbIdentity(_bb, new FbsKrbIdentity()); }
+  public static FbsKrbIdentity getRootAsFbsKrbIdentity(ByteBuffer _bb, FbsKrbIdentity obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public FbsKrbIdentity __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public FbsPrincipalName principal() { return principal(new FbsPrincipalName()); }
+  public FbsPrincipalName principal(FbsPrincipalName obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+  public int keyVersion() { int o = __offset(6); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateKeyVersion(int keyVersion) { int o = __offset(6); if (o != 0) { bb.putInt(o + bb_pos, keyVersion); return true; } else { return false; } }
+  public int kdcFlags() { int o = __offset(8); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateKdcFlags(int kdcFlags) { int o = __offset(8); if (o != 0) { bb.putInt(o + bb_pos, kdcFlags); return true; } else { return false; } }
+  public boolean disabled() { int o = __offset(10); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
+  public boolean mutateDisabled(boolean disabled) { int o = __offset(10); if (o != 0) { bb.put(o + bb_pos, (byte)(disabled ? 1 : 0)); return true; } else { return false; } }
+  public FbsEncryptionKey keys(int j) { return keys(new FbsEncryptionKey(), j); }
+  public FbsEncryptionKey keys(FbsEncryptionKey obj, int j) { int o = __offset(12); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
+  public int keysLength() { int o = __offset(12); return o != 0 ? __vector_len(o) : 0; }
+
+  public static int createFbsKrbIdentity(FlatBufferBuilder builder,
+      int principal,
+      int keyVersion,
+      int kdcFlags,
+      boolean disabled,
+      int keys) {
+    builder.startObject(5);
+    FbsKrbIdentity.addKeys(builder, keys);
+    FbsKrbIdentity.addKdcFlags(builder, kdcFlags);
+    FbsKrbIdentity.addKeyVersion(builder, keyVersion);
+    FbsKrbIdentity.addPrincipal(builder, principal);
+    FbsKrbIdentity.addDisabled(builder, disabled);
+    return FbsKrbIdentity.endFbsKrbIdentity(builder);
+  }
+
+  public static void startFbsKrbIdentity(FlatBufferBuilder builder) { builder.startObject(5); }
+  public static void addPrincipal(FlatBufferBuilder builder, int principalOffset) { builder.addOffset(0, principalOffset, 0); }
+  public static void addKeyVersion(FlatBufferBuilder builder, int keyVersion) { builder.addInt(1, keyVersion, 0); }
+  public static void addKdcFlags(FlatBufferBuilder builder, int kdcFlags) { builder.addInt(2, kdcFlags, 0); }
+  public static void addDisabled(FlatBufferBuilder builder, boolean disabled) { builder.addBoolean(3, disabled, false); }
+  public static void addKeys(FlatBufferBuilder builder, int keysOffset) { builder.addOffset(4, keysOffset, 0); }
+  public static int createKeysVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+  public static void startKeysVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+  public static int endFbsKrbIdentity(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsPrincipalName.java b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsPrincipalName.java
new file mode 100644
index 0000000..baef55c
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FbsPrincipalName.java
@@ -0,0 +1,38 @@
+// automatically generated, do not modify
+
+package org.apache.kerby.kerberos.kdc.identitybackend;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class FbsPrincipalName extends Table {
+  public static FbsPrincipalName getRootAsFbsPrincipalName(ByteBuffer _bb) { return getRootAsFbsPrincipalName(_bb, new FbsPrincipalName()); }
+  public static FbsPrincipalName getRootAsFbsPrincipalName(ByteBuffer _bb, FbsPrincipalName obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public FbsPrincipalName __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public int nameType() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateNameType(int nameType) { int o = __offset(4); if (o != 0) { bb.putInt(o + bb_pos, nameType); return true; } else { return false; } }
+  public String nameString() { int o = __offset(6); return o != 0 ? __string(o + bb_pos) : null; }
+  public ByteBuffer nameStringAsByteBuffer() { return __vector_as_bytebuffer(6, 1); }
+
+  public static int createFbsPrincipalName(FlatBufferBuilder builder,
+      int nameType,
+      int nameString) {
+    builder.startObject(2);
+    FbsPrincipalName.addNameString(builder, nameString);
+    FbsPrincipalName.addNameType(builder, nameType);
+    return FbsPrincipalName.endFbsPrincipalName(builder);
+  }
+
+  public static void startFbsPrincipalName(FlatBufferBuilder builder) { builder.startObject(2); }
+  public static void addNameType(FlatBufferBuilder builder, int nameType) { builder.addInt(0, nameType, 0); }
+  public static void addNameString(FlatBufferBuilder builder, int nameStringOffset) { builder.addOffset(1, nameStringOffset, 0); }
+  public static int endFbsPrincipalName(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FlatbuffersIdentityBackend.java b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FlatbuffersIdentityBackend.java
new file mode 100644
index 0000000..57c8bc4
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/FlatbuffersIdentityBackend.java
@@ -0,0 +1,197 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kdc.identitybackend;
+
+import com.google.flatbuffers.FlatBufferBuilder;
+import org.apache.kerby.config.Config;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.identity.backend.AbstractIdentityBackend;
+import org.apache.kerby.util.IOUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A Flatbuffers backed backend implementation.
+ *
+ */
+public class FlatbuffersIdentityBackend extends AbstractIdentityBackend {
+    private static final Logger LOG =
+            LoggerFactory.getLogger(FlatbuffersIdentityBackend.class);
+    public static final String FBS_IDENTITY_BACKEND_DIR =
+            "backend.flatbuffers.dir";
+    private File fbsKdbFile;
+    private FlatBufferBuilder fbsBuilder;
+    private long kdbFileTimeStamp;
+
+    // Identities loaded from file
+    private final Map<String, KrbIdentity> identities =
+        new ConcurrentHashMap<>(new TreeMap<String, KrbIdentity>());
+
+    public FlatbuffersIdentityBackend() {
+
+    }
+
+    /**
+     * Constructing an instance using specified config that contains anything
+     * to be used to initialize the fbs format database.
+     * @param config The configuration for fbs identity backend
+     */
+    public FlatbuffersIdentityBackend(Config config) {
+        setConfig(config);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doInitialize() throws KrbException {
+        LOG.info("Initializing the Flatbuffers identity backend.");
+        createFbsBuilder();
+        load();
+    }
+
+    /**
+     * Load identities from file
+     */
+    private void load() throws KrbException {
+        LOG.info("Loading the identities from fbs file.");
+        String fbsFile = getConfig().getString(FBS_IDENTITY_BACKEND_DIR);
+        File fbsFileDir;
+        if (fbsFile == null || fbsFile.isEmpty()) {
+            fbsFileDir = getBackendConfig().getConfDir();
+        } else {
+            fbsFileDir = new File(fbsFile);
+            if (!fbsFileDir.exists() && !fbsFileDir.mkdirs()) {
+                throw new KrbException("could not create fbs file dir " + fbsFileDir);
+            }
+        }
+
+        fbsKdbFile = new File(fbsFileDir, "fbs-backend.bin");
+
+        if (!fbsKdbFile.exists()) {
+            try {
+                fbsKdbFile.createNewFile();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        checkAndLoad();
+    }
+
+    /**
+     * Check kdb file timestamp to see if it's changed or not. If
+     * necessary load the kdb again.
+     */
+    private synchronized void checkAndLoad() throws KrbException {
+        long nowTimeStamp = fbsKdbFile.lastModified();
+
+        if (kdbFileTimeStamp == 0 || nowTimeStamp != kdbFileTimeStamp) {
+            //load identities
+            String existsFbsFile = null;
+            try {
+                existsFbsFile = IOUtil.readFile(fbsKdbFile);
+            } catch (IOException e) {
+                throw new KrbException("Failed to read file", e);
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected KrbIdentity doGetIdentity(String principalName) throws KrbException {
+        checkAndLoad();
+        return identities.get(principalName);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected KrbIdentity doAddIdentity(KrbIdentity identity) throws KrbException {
+        checkAndLoad();
+
+        identities.put(identity.getPrincipalName(), identity);
+        idsToFile(identities);
+
+        return doGetIdentity(identity.getPrincipalName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected KrbIdentity doUpdateIdentity(KrbIdentity identity) throws KrbException {
+        checkAndLoad();
+        identities.put(identity.getPrincipalName(), identity);
+        idsToFile(identities);
+
+        return doGetIdentity(identity.getPrincipalName());
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doDeleteIdentity(String principalName) throws KrbException {
+        checkAndLoad();
+        if (identities.containsKey(principalName)) {
+            identities.remove(principalName);
+        }
+        idsToFile(identities);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Iterable<String> doGetIdentities() throws KrbException {
+        List<String> principals = new ArrayList<>(identities.keySet());
+        Collections.sort(principals);
+
+        return principals;
+    }
+
+    private void createFbsBuilder() {
+        fbsBuilder = new FlatBufferBuilder();
+    }
+
+    /**
+     * Write identities into a file
+     * @param ids the identities to write into the fbs file
+     */
+    private synchronized void idsToFile(Map<String, KrbIdentity> ids) throws KrbException {
+        String newFbsFile = null;
+        try {
+            IOUtil.writeFile(newFbsFile, fbsKdbFile);
+        } catch (IOException e) {
+            LOG.error("Error occurred while writing identities to file: " + fbsKdbFile);
+            throw new KrbException("Failed to write file", e);
+        }
+    }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/schema/include_test1.fbs b/kerby-backend/flatbuffers-backend/src/schema/include_test1.fbs
new file mode 100644
index 0000000..11aebe8
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/schema/include_test1.fbs
@@ -0,0 +1,5 @@
+include "include_test2.fbs";
+include "include_test2.fbs";  // should be skipped
+include "include_test1.fbs";  // should be skipped
+
+
diff --git a/kerby-backend/flatbuffers-backend/src/schema/include_test2.fbs b/kerby-backend/flatbuffers-backend/src/schema/include_test2.fbs
new file mode 100644
index 0000000..d22c0d9
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/schema/include_test2.fbs
@@ -0,0 +1,9 @@
+include "include_test2.fbs";    // should be skipped
+
+namespace MyGame.OtherNameSpace;
+
+enum FromInclude:long { IncludeVal }
+
+struct Unused {}
+
+
diff --git a/kerby-backend/flatbuffers-backend/src/schema/kerby.fbs b/kerby-backend/flatbuffers-backend/src/schema/kerby.fbs
new file mode 100644
index 0000000..a4eea19
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/schema/kerby.fbs
@@ -0,0 +1,28 @@
+// Kerby KDC backend schema file
+
+namespace org.apache.kerby.kerberos.kdc.identitybackend;
+
+table FbsPrincipalName {
+  nameType:int;
+  nameString:string;
+}
+
+table FbsEncryptionKey {
+  keyType:int;
+  keyValue:[byte];
+}
+
+table FbsKrbIdentity {
+  principal:FbsPrincipalName;
+  keyVersion:int;
+  kdcFlags:int;
+  disabled:bool;
+  keys:[FbsEncryptionKey];
+}
+
+table FbsKerby {
+  name:string;
+  identities:[FbsKrbIdentity];
+}
+
+root_type FbsKerby;
\ No newline at end of file
diff --git a/kerby-backend/flatbuffers-backend/src/schema/monster_test.fbs b/kerby-backend/flatbuffers-backend/src/schema/monster_test.fbs
new file mode 100644
index 0000000..b2b99bb
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/schema/monster_test.fbs
@@ -0,0 +1,66 @@
+// test schema file
+
+include "include_test1.fbs";
+
+namespace MyGame.Example;
+
+attribute "priority";
+
+enum Color:byte (bit_flags) { Red = 0, Green, Blue = 3, }
+
+union Any { Monster, TestSimpleTableWithEnum }  // TODO: add more elements
+
+struct Test { a:short; b:byte; }
+
+table TestSimpleTableWithEnum {
+  color: Color = Green;
+}
+
+struct Vec3 (force_align: 16) {
+  x:float;
+  y:float;
+  z:float;
+  test1:double;
+  test2:Color;
+  test3:Test;
+}
+
+table Stat {
+  id:string;
+  val:long;
+  count:ushort;
+}
+
+table Monster {
+  pos:Vec3 (id: 0);
+  hp:short = 100 (id: 2);
+  mana:short = 150 (id: 1);
+  name:string (id: 3, required, key);
+  color:Color = Blue (id: 6);
+  inventory:[ubyte] (id: 5);
+  friendly:bool = false (deprecated, priority: 1, id: 4);
+  /// an example documentation comment: this will end up in the generated code
+  /// multiline too
+  testarrayoftables:[Monster] (id: 11);
+  testarrayofstring:[string] (id: 10);
+  testarrayofbools:[bool] (id: 24);
+  enemy:MyGame.Example.Monster (id:12);  // Test referring by full namespace.
+  test:Any (id: 8);
+  test4:[Test] (id: 9);
+  testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
+  testempty:Stat (id:14);
+  testbool:bool (id:15);
+  testhashs32_fnv1:int (id:16, hash:"fnv1_32");
+  testhashu32_fnv1:uint (id:17, hash:"fnv1_32");
+  testhashs64_fnv1:long (id:18, hash:"fnv1_64");
+  testhashu64_fnv1:ulong (id:19, hash:"fnv1_64");
+  testhashs32_fnv1a:int (id:20, hash:"fnv1a_32");
+  testhashu32_fnv1a:uint (id:21, hash:"fnv1a_32");
+  testhashs64_fnv1a:long (id:22, hash:"fnv1a_64");
+  testhashu64_fnv1a:ulong (id:23, hash:"fnv1a_64");
+}
+
+root_type Monster;
+
+file_identifier "MONS";
+file_extension "mon";
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/JavaTest.java b/kerby-backend/flatbuffers-backend/src/test/java/JavaTest.java
new file mode 100644
index 0000000..936bca5
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/JavaTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import MyGame.Example.*;
+import com.google.flatbuffers.FlatBufferBuilder;
+
+class JavaTest {
+    public static void main(String[] args) {
+
+        // First, let's test reading a FlatBuffer generated by C++ code:
+        // This file was generated from monsterdata_test.json
+
+        byte[] data = null;
+        File file = new File("C:\\work\\projects\\kerby\\kerby-backend\\flatbuffers-backend\\src\\test\\monsterdata_test.mon");
+        RandomAccessFile f = null;
+        try {
+            f = new RandomAccessFile(file, "r");
+            data = new byte[(int)f.length()];
+            f.readFully(data);
+            f.close();
+        } catch(IOException e) {
+            System.out.println("FlatBuffers test: couldn't read file");
+            return;
+        }
+
+        // Now test it:
+
+        ByteBuffer bb = ByteBuffer.wrap(data);
+        TestBuffer(bb);
+
+        FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+
+        // We set up the same values as monsterdata.json:
+
+        int str = fbb.createString("MyMonster");
+        // Second, let's create a FlatBuffer from scratch in Java, and test it also.
+        // We use an initial size of 1 to exercise the reallocation algorithm,
+        // normally a size larger than the typical FlatBuffer you generate would be
+        // better for performance.
+
+        int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
+
+        int fred = fbb.createString("Fred");
+        Monster.startMonster(fbb);
+        Monster.addName(fbb, fred);
+        int mon2 = Monster.endMonster(fbb);
+
+        Monster.startTest4Vector(fbb, 2);
+        Test.createTest(fbb, (short)10, (byte)20);
+        Test.createTest(fbb, (short)30, (byte)40);
+        int test4 = fbb.endVector();
+
+        int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
+            fbb.createString("test1"),
+            fbb.createString("test2")
+        });
+
+        Monster.startMonster(fbb);
+        Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+                                                 Color.Green, (short)5, (byte)6));
+        Monster.addHp(fbb, (short)80);
+        Monster.addName(fbb, str);
+        Monster.addInventory(fbb, inv);
+        Monster.addTestType(fbb, (byte)Any.Monster);
+        Monster.addTest(fbb, mon2);
+        Monster.addTest4(fbb, test4);
+        Monster.addTestarrayofstring(fbb, testArrayOfString);
+        Monster.addTestbool(fbb, false);
+        Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
+        int mon = Monster.endMonster(fbb);
+
+        Monster.finishMonsterBuffer(fbb, mon);
+
+        // Write the result to a file for debugging purposes:
+        // Note that the binaries are not necessarily identical, since the JSON
+        // parser may serialize in a slightly different order than the above
+        // Java code. They are functionally equivalent though.
+
+        try {
+            DataOutputStream os = new DataOutputStream(new FileOutputStream(
+                                           "monsterdata_java_wire.mon"));
+            os.write(fbb.dataBuffer().array(), fbb.dataBuffer().position(), fbb.offset());
+            os.close();
+        } catch(IOException e) {
+            System.out.println("FlatBuffers test: couldn't write file");
+            return;
+        }
+
+        // Test it:
+        TestExtendedBuffer(fbb.dataBuffer());
+
+        // Make sure it also works with read only ByteBuffers. This is slower,
+        // since creating strings incurs an additional copy
+        // (see Table.__string).
+        TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
+
+        TestEnums();
+
+        //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
+        // revert to original values after testing
+        Monster monster = Monster.getRootAsMonster(fbb.dataBuffer());
+
+        // mana is optional and does not exist in the buffer so the mutation should fail
+        // the mana field should retain its default value
+        TestEq(monster.mutateMana((short)10), false);
+        TestEq(monster.mana(), (short)150);
+
+        // testType is an existing field and mutating it should succeed
+        TestEq(monster.testType(), (byte)Any.Monster);
+        TestEq(monster.mutateTestType(Any.NONE), true);
+        TestEq(monster.testType(), (byte)Any.NONE);
+        TestEq(monster.mutateTestType(Any.Monster), true);
+        TestEq(monster.testType(), (byte)Any.Monster);
+
+        //mutate the inventory vector
+        TestEq(monster.mutateInventory(0, 1), true);
+        TestEq(monster.mutateInventory(1, 2), true);
+        TestEq(monster.mutateInventory(2, 3), true);
+        TestEq(monster.mutateInventory(3, 4), true);
+        TestEq(monster.mutateInventory(4, 5), true);
+
+        for (int i = 0; i < monster.inventoryLength(); i++) {
+            TestEq(monster.inventory(i), i + 1);
+        }
+
+        //reverse mutation
+        TestEq(monster.mutateInventory(0, 0), true);
+        TestEq(monster.mutateInventory(1, 1), true);
+        TestEq(monster.mutateInventory(2, 2), true);
+        TestEq(monster.mutateInventory(3, 3), true);
+        TestEq(monster.mutateInventory(4, 4), true);
+
+        // get a struct field and edit one of its fields
+        Vec3 pos = monster.pos();
+        TestEq(pos.x(), 1.0f);
+        pos.mutateX(55.0f);
+        TestEq(pos.x(), 55.0f);
+        pos.mutateX(1.0f);
+        TestEq(pos.x(), 1.0f);
+
+        TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
+
+        System.out.println("FlatBuffers test: completed successfully");
+    }
+
+    static void TestEnums() {
+      TestEq(Color.name(Color.Red), "Red");
+      TestEq(Color.name(Color.Blue), "Blue");
+      TestEq(Any.name(Any.NONE), "NONE");
+      TestEq(Any.name(Any.Monster), "Monster");
+    }
+
+    static void TestBuffer(ByteBuffer bb) {
+        TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
+        
+        Monster monster = Monster.getRootAsMonster(bb);
+
+        TestEq(monster.hp(), (short)80);
+        TestEq(monster.mana(), (short)150);  // default
+
+        TestEq(monster.name(), "MyMonster");
+        // monster.friendly() // can't access, deprecated
+
+        Vec3 pos = monster.pos();
+        TestEq(pos.x(), 1.0f);
+        TestEq(pos.y(), 2.0f);
+        TestEq(pos.z(), 3.0f);
+        TestEq(pos.test1(), 3.0);
+        TestEq(pos.test2(), Color.Green);
+        Test t = pos.test3();
+        TestEq(t.a(), (short)5);
+        TestEq(t.b(), (byte)6);
+
+        TestEq(monster.testType(), (byte)Any.Monster);
+        Monster monster2 = new Monster();
+        TestEq(monster.test(monster2) != null, true);
+        TestEq(monster2.name(), "Fred");
+
+        TestEq(monster.inventoryLength(), 5);
+        int invsum = 0;
+        for (int i = 0; i < monster.inventoryLength(); i++)
+            invsum += monster.inventory(i);
+        TestEq(invsum, 10);
+
+        // Alternative way of accessing a vector:
+        ByteBuffer ibb = monster.inventoryAsByteBuffer();
+        invsum = 0;
+        while (ibb.position() < ibb.limit())
+            invsum += ibb.get();
+        TestEq(invsum, 10);
+
+        Test test_0 = monster.test4(0);
+        Test test_1 = monster.test4(1);
+        TestEq(monster.test4Length(), 2);
+        TestEq(test_0.a() + test_0.b() + test_1.a() + test_1.b(), 100);
+
+        TestEq(monster.testarrayofstringLength(), 2);
+        TestEq(monster.testarrayofstring(0),"test1");
+        TestEq(monster.testarrayofstring(1),"test2");
+
+        TestEq(monster.testbool(), false);
+    }
+
+    // this method checks additional fields not present in the binary buffer read from file
+    // these new tests are performed on top of the regular tests
+    static void TestExtendedBuffer(ByteBuffer bb) {
+        TestBuffer(bb);
+
+        Monster monster = Monster.getRootAsMonster(bb);
+
+        TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
+    }
+
+    static <T> void TestEq(T a, T b) {
+        if (!a.equals(b)) {
+            System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
+            System.out.println("FlatBuffers test FAILED: \'" + a + "\' != \'" + b + "\'");
+            assert false;
+            System.exit(1);
+        }
+    }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Any.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Any.java
new file mode 100644
index 0000000..cdc3ec5
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Any.java
@@ -0,0 +1,15 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+public final class Any {
+  private Any() { }
+  public static final byte NONE = 0;
+  public static final byte Monster = 1;
+  public static final byte TestSimpleTableWithEnum = 2;
+
+  private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", };
+
+  public static String name(int e) { return names[e]; }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Color.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Color.java
new file mode 100644
index 0000000..822d2bb
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Color.java
@@ -0,0 +1,15 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+public final class Color {
+  private Color() { }
+  public static final byte Red = 1;
+  public static final byte Green = 2;
+  public static final byte Blue = 8;
+
+  private static final String[] names = { "Red", "Green", "", "", "", "", "", "Blue", };
+
+  public static String name(int e) { return names[e - Red]; }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Monster.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Monster.java
new file mode 100644
index 0000000..9f97590
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Monster.java
@@ -0,0 +1,120 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Monster extends Table {
+  public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
+  public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public static boolean MonsterBufferHasIdentifier(ByteBuffer _bb) { return __has_identifier(_bb, "MONS"); }
+  public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public Vec3 pos() { return pos(new Vec3()); }
+  public Vec3 pos(Vec3 obj) { int o = __offset(4); return o != 0 ? obj.__init(o + bb_pos, bb) : null; }
+  public short mana() { int o = __offset(6); return o != 0 ? bb.getShort(o + bb_pos) : 150; }
+  public boolean mutateMana(short mana) { int o = __offset(6); if (o != 0) { bb.putShort(o + bb_pos, mana); return true; } else { return false; } }
+  public short hp() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 100; }
+  public boolean mutateHp(short hp) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, hp); return true; } else { return false; } }
+  public String name() { int o = __offset(10); return o != 0 ? __string(o + bb_pos) : null; }
+  public ByteBuffer nameAsByteBuffer() { return __vector_as_bytebuffer(10, 1); }
+  public int inventory(int j) { int o = __offset(14); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+  public int inventoryLength() { int o = __offset(14); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer inventoryAsByteBuffer() { return __vector_as_bytebuffer(14, 1); }
+  public boolean mutateInventory(int j, int inventory) { int o = __offset(14); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)inventory); return true; } else { return false; } }
+  public byte color() { int o = __offset(16); return o != 0 ? bb.get(o + bb_pos) : 8; }
+  public boolean mutateColor(byte color) { int o = __offset(16); if (o != 0) { bb.put(o + bb_pos, color); return true; } else { return false; } }
+  public byte testType() { int o = __offset(18); return o != 0 ? bb.get(o + bb_pos) : 0; }
+  public boolean mutateTestType(byte test_type) { int o = __offset(18); if (o != 0) { bb.put(o + bb_pos, test_type); return true; } else { return false; } }
+  public Table test(Table obj) { int o = __offset(20); return o != 0 ? __union(obj, o) : null; }
+  public Test test4(int j) { return test4(new Test(), j); }
+  public Test test4(Test obj, int j) { int o = __offset(22); return o != 0 ? obj.__init(__vector(o) + j * 4, bb) : null; }
+  public int test4Length() { int o = __offset(22); return o != 0 ? __vector_len(o) : 0; }
+  public String testarrayofstring(int j) { int o = __offset(24); return o != 0 ? __string(__vector(o) + j * 4) : null; }
+  public int testarrayofstringLength() { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; }
+  /**
+   * an example documentation comment: this will end up in the generated code
+   * multiline too
+   */
+  public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); }
+  public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__init(__indirect(__vector(o) + j * 4), bb) : null; }
+  public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
+  public Monster enemy() { return enemy(new Monster()); }
+  public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+  public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+  public int testnestedflatbufferLength() { int o = __offset(30); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer testnestedflatbufferAsByteBuffer() { return __vector_as_bytebuffer(30, 1); }
+  public boolean mutateTestnestedflatbuffer(int j, int testnestedflatbuffer) { int o = __offset(30); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)testnestedflatbuffer); return true; } else { return false; } }
+  public Stat testempty() { return testempty(new Stat()); }
+  public Stat testempty(Stat obj) { int o = __offset(32); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
+  public boolean testbool() { int o = __offset(34); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
+  public boolean mutateTestbool(boolean testbool) { int o = __offset(34); if (o != 0) { bb.put(o + bb_pos, (byte)(testbool ? 1 : 0)); return true; } else { return false; } }
+  public int testhashs32Fnv1() { int o = __offset(36); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateTesthashs32Fnv1(int testhashs32_fnv1) { int o = __offset(36); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1); return true; } else { return false; } }
+  public long testhashu32Fnv1() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
+  public boolean mutateTesthashu32Fnv1(long testhashu32_fnv1) { int o = __offset(38); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1); return true; } else { return false; } }
+  public long testhashs64Fnv1() { int o = __offset(40); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+  public boolean mutateTesthashs64Fnv1(long testhashs64_fnv1) { int o = __offset(40); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1); return true; } else { return false; } }
+  public long testhashu64Fnv1() { int o = __offset(42); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+  public boolean mutateTesthashu64Fnv1(long testhashu64_fnv1) { int o = __offset(42); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1); return true; } else { return false; } }
+  public int testhashs32Fnv1a() { int o = __offset(44); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateTesthashs32Fnv1a(int testhashs32_fnv1a) { int o = __offset(44); if (o != 0) { bb.putInt(o + bb_pos, testhashs32_fnv1a); return true; } else { return false; } }
+  public long testhashu32Fnv1a() { int o = __offset(46); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0; }
+  public boolean mutateTesthashu32Fnv1a(long testhashu32_fnv1a) { int o = __offset(46); if (o != 0) { bb.putInt(o + bb_pos, (int)testhashu32_fnv1a); return true; } else { return false; } }
+  public long testhashs64Fnv1a() { int o = __offset(48); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+  public boolean mutateTesthashs64Fnv1a(long testhashs64_fnv1a) { int o = __offset(48); if (o != 0) { bb.putLong(o + bb_pos, testhashs64_fnv1a); return true; } else { return false; } }
+  public long testhashu64Fnv1a() { int o = __offset(50); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+  public boolean mutateTesthashu64Fnv1a(long testhashu64_fnv1a) { int o = __offset(50); if (o != 0) { bb.putLong(o + bb_pos, testhashu64_fnv1a); return true; } else { return false; } }
+  public boolean testarrayofbools(int j) { int o = __offset(52); return o != 0 ? 0!=bb.get(__vector(o) + j * 1) : false; }
+  public int testarrayofboolsLength() { int o = __offset(52); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer testarrayofboolsAsByteBuffer() { return __vector_as_bytebuffer(52, 1); }
+  public boolean mutateTestarrayofbools(int j, boolean testarrayofbools) { int o = __offset(52); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)(testarrayofbools ? 1 : 0)); return true; } else { return false; } }
+
+  public static void startMonster(FlatBufferBuilder builder) { builder.startObject(25); }
+  public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
+  public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
+  public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
+  public static void addName(FlatBufferBuilder builder, int nameOffset) { builder.addOffset(3, nameOffset, 0); }
+  public static void addInventory(FlatBufferBuilder builder, int inventoryOffset) { builder.addOffset(5, inventoryOffset, 0); }
+  public static int createInventoryVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+  public static void startInventoryVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(6, color, 8); }
+  public static void addTestType(FlatBufferBuilder builder, byte testType) { builder.addByte(7, testType, 0); }
+  public static void addTest(FlatBufferBuilder builder, int testOffset) { builder.addOffset(8, testOffset, 0); }
+  public static void addTest4(FlatBufferBuilder builder, int test4Offset) { builder.addOffset(9, test4Offset, 0); }
+  public static void startTest4Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
+  public static void addTestarrayofstring(FlatBufferBuilder builder, int testarrayofstringOffset) { builder.addOffset(10, testarrayofstringOffset, 0); }
+  public static int createTestarrayofstringVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+  public static void startTestarrayofstringVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+  public static void addTestarrayoftables(FlatBufferBuilder builder, int testarrayoftablesOffset) { builder.addOffset(11, testarrayoftablesOffset, 0); }
+  public static int createTestarrayoftablesVector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
+  public static void startTestarrayoftablesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+  public static void addEnemy(FlatBufferBuilder builder, int enemyOffset) { builder.addOffset(12, enemyOffset, 0); }
+  public static void addTestnestedflatbuffer(FlatBufferBuilder builder, int testnestedflatbufferOffset) { builder.addOffset(13, testnestedflatbufferOffset, 0); }
+  public static int createTestnestedflatbufferVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+  public static void startTestnestedflatbufferVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static void addTestempty(FlatBufferBuilder builder, int testemptyOffset) { builder.addOffset(14, testemptyOffset, 0); }
+  public static void addTestbool(FlatBufferBuilder builder, boolean testbool) { builder.addBoolean(15, testbool, false); }
+  public static void addTesthashs32Fnv1(FlatBufferBuilder builder, int testhashs32Fnv1) { builder.addInt(16, testhashs32Fnv1, 0); }
+  public static void addTesthashu32Fnv1(FlatBufferBuilder builder, long testhashu32Fnv1) { builder.addInt(17, (int)(testhashu32Fnv1 & 0xFFFFFFFFL), 0); }
+  public static void addTesthashs64Fnv1(FlatBufferBuilder builder, long testhashs64Fnv1) { builder.addLong(18, testhashs64Fnv1, 0); }
+  public static void addTesthashu64Fnv1(FlatBufferBuilder builder, long testhashu64Fnv1) { builder.addLong(19, testhashu64Fnv1, 0); }
+  public static void addTesthashs32Fnv1a(FlatBufferBuilder builder, int testhashs32Fnv1a) { builder.addInt(20, testhashs32Fnv1a, 0); }
+  public static void addTesthashu32Fnv1a(FlatBufferBuilder builder, long testhashu32Fnv1a) { builder.addInt(21, (int)(testhashu32Fnv1a & 0xFFFFFFFFL), 0); }
+  public static void addTesthashs64Fnv1a(FlatBufferBuilder builder, long testhashs64Fnv1a) { builder.addLong(22, testhashs64Fnv1a, 0); }
+  public static void addTesthashu64Fnv1a(FlatBufferBuilder builder, long testhashu64Fnv1a) { builder.addLong(23, testhashu64Fnv1a, 0); }
+  public static void addTestarrayofbools(FlatBufferBuilder builder, int testarrayofboolsOffset) { builder.addOffset(24, testarrayofboolsOffset, 0); }
+  public static int createTestarrayofboolsVector(FlatBufferBuilder builder, boolean[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addBoolean(data[i]); return builder.endVector(); }
+  public static void startTestarrayofboolsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static int endMonster(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    builder.required(o, 10);  // name
+    return o;
+  }
+  public static void finishMonsterBuffer(FlatBufferBuilder builder, int offset) { builder.finish(offset, "MONS"); }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Stat.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Stat.java
new file mode 100644
index 0000000..73f9562
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Stat.java
@@ -0,0 +1,43 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Stat extends Table {
+  public static Stat getRootAsStat(ByteBuffer _bb) { return getRootAsStat(_bb, new Stat()); }
+  public static Stat getRootAsStat(ByteBuffer _bb, Stat obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public Stat __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public String id() { int o = __offset(4); return o != 0 ? __string(o + bb_pos) : null; }
+  public ByteBuffer idAsByteBuffer() { return __vector_as_bytebuffer(4, 1); }
+  public long val() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0; }
+  public boolean mutateVal(long val) { int o = __offset(6); if (o != 0) { bb.putLong(o + bb_pos, val); return true; } else { return false; } }
+  public int count() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
+  public boolean mutateCount(int count) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, (short)count); return true; } else { return false; } }
+
+  public static int createStat(FlatBufferBuilder builder,
+      int id,
+      long val,
+      int count) {
+    builder.startObject(3);
+    Stat.addVal(builder, val);
+    Stat.addId(builder, id);
+    Stat.addCount(builder, count);
+    return Stat.endStat(builder);
+  }
+
+  public static void startStat(FlatBufferBuilder builder) { builder.startObject(3); }
+  public static void addId(FlatBufferBuilder builder, int idOffset) { builder.addOffset(0, idOffset, 0); }
+  public static void addVal(FlatBufferBuilder builder, long val) { builder.addLong(1, val, 0); }
+  public static void addCount(FlatBufferBuilder builder, int count) { builder.addShort(2, (short)(count & 0xFFFF), 0); }
+  public static int endStat(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Test.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Test.java
new file mode 100644
index 0000000..ffd7394
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Test.java
@@ -0,0 +1,27 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Test extends Struct {
+  public Test __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public short a() { return bb.getShort(bb_pos + 0); }
+  public void mutateA(short a) { bb.putShort(bb_pos + 0, a); }
+  public byte b() { return bb.get(bb_pos + 2); }
+  public void mutateB(byte b) { bb.put(bb_pos + 2, b); }
+
+  public static int createTest(FlatBufferBuilder builder, short a, byte b) {
+    builder.prep(2, 4);
+    builder.pad(1);
+    builder.putByte(b);
+    builder.putShort(a);
+    return builder.offset();
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/TestSimpleTableWithEnum.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/TestSimpleTableWithEnum.java
new file mode 100644
index 0000000..3000cab
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/TestSimpleTableWithEnum.java
@@ -0,0 +1,33 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TestSimpleTableWithEnum extends Table {
+  public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb) { return getRootAsTestSimpleTableWithEnum(_bb, new TestSimpleTableWithEnum()); }
+  public static TestSimpleTableWithEnum getRootAsTestSimpleTableWithEnum(ByteBuffer _bb, TestSimpleTableWithEnum obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public TestSimpleTableWithEnum __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public byte color() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 2; }
+  public boolean mutateColor(byte color) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, color); return true; } else { return false; } }
+
+  public static int createTestSimpleTableWithEnum(FlatBufferBuilder builder,
+      byte color) {
+    builder.startObject(1);
+    TestSimpleTableWithEnum.addColor(builder, color);
+    return TestSimpleTableWithEnum.endTestSimpleTableWithEnum(builder);
+  }
+
+  public static void startTestSimpleTableWithEnum(FlatBufferBuilder builder) { builder.startObject(1); }
+  public static void addColor(FlatBufferBuilder builder, byte color) { builder.addByte(0, color, 2); }
+  public static int endTestSimpleTableWithEnum(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Vec3.java b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Vec3.java
new file mode 100644
index 0000000..86edb6d
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/MyGame/Example/Vec3.java
@@ -0,0 +1,44 @@
+// automatically generated, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Vec3 extends Struct {
+  public Vec3 __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
+
+  public float x() { return bb.getFloat(bb_pos + 0); }
+  public void mutateX(float x) { bb.putFloat(bb_pos + 0, x); }
+  public float y() { return bb.getFloat(bb_pos + 4); }
+  public void mutateY(float y) { bb.putFloat(bb_pos + 4, y); }
+  public float z() { return bb.getFloat(bb_pos + 8); }
+  public void mutateZ(float z) { bb.putFloat(bb_pos + 8, z); }
+  public double test1() { return bb.getDouble(bb_pos + 16); }
+  public void mutateTest1(double test1) { bb.putDouble(bb_pos + 16, test1); }
+  public byte test2() { return bb.get(bb_pos + 24); }
+  public void mutateTest2(byte test2) { bb.put(bb_pos + 24, test2); }
+  public Test test3() { return test3(new Test()); }
+  public Test test3(Test obj) { return obj.__init(bb_pos + 26, bb); }
+
+  public static int createVec3(FlatBufferBuilder builder, float x, float y, float z, double test1, byte test2, short test3_a, byte test3_b) {
+    builder.prep(16, 32);
+    builder.pad(2);
+    builder.prep(2, 4);
+    builder.pad(1);
+    builder.putByte(test3_b);
+    builder.putShort(test3_a);
+    builder.pad(1);
+    builder.putByte(test2);
+    builder.putDouble(test1);
+    builder.pad(4);
+    builder.putFloat(z);
+    builder.putFloat(y);
+    builder.putFloat(x);
+    return builder.offset();
+  }
+};
+
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTest.java b/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTest.java
new file mode 100644
index 0000000..aa3b4eb
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTest.java
@@ -0,0 +1,56 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.kerby.kerberos.kerb.identity.backend;
+
+import org.apache.kerby.config.Conf;
+import org.apache.kerby.config.Config;
+import org.apache.kerby.kerberos.kdc.identitybackend.FlatbuffersIdentityBackend;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import java.io.File;
+
+/**
+ * Flatbuffers backend test
+ */
+public class FlatbuffersBackendTest extends BackendTestBase {
+    private static File fbsBackendFile;
+
+    @BeforeClass
+    public static void setup() throws KrbException {
+        File testDir = new File(System.getProperty("test.dir", "target"));
+        fbsBackendFile = new File(testDir, "fbs-identity-backend-file");
+        String jsonBackendFileString = fbsBackendFile.getAbsolutePath();
+
+        Config backendConfig = new Conf();
+        backendConfig.setString(FlatbuffersIdentityBackend.FBS_IDENTITY_BACKEND_DIR,
+                jsonBackendFileString);
+        backend = new FlatbuffersIdentityBackend(backendConfig);
+        backend.initialize();
+    }
+
+    @AfterClass
+    public static void cleanJsonBackendFile() {
+        if (fbsBackendFile.exists()) {
+            fbsBackendFile.delete();
+        }
+    }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTestUtil.java b/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTestUtil.java
new file mode 100644
index 0000000..8061ae5
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/FlatbuffersBackendTestUtil.java
@@ -0,0 +1,77 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *
+ */
+package org.apache.kerby.kerberos.kerb.identity.backend;
+
+import MyGame.Example.*;
+import com.google.flatbuffers.FlatBufferBuilder;
+import org.apache.kerby.kerberos.kdc.identitybackend.FbsEncryptionKey;
+import org.apache.kerby.kerberos.kdc.identitybackend.FbsKerby;
+import org.apache.kerby.kerberos.kdc.identitybackend.FbsKrbIdentity;
+import org.apache.kerby.kerberos.kdc.identitybackend.FbsPrincipalName;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.KrbIdentity;
+import org.apache.kerby.kerberos.kerb.spec.base.EncryptionKey;
+import org.apache.kerby.kerberos.kerb.spec.base.PrincipalName;
+
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Flatbuffers test utilities
+ */
+public class FlatbuffersBackendTestUtil {
+
+    public static void main(String[] args) throws KrbException {
+        List<KrbIdentity> idendenties = BackendTestUtil.createManyIdentities(2);
+
+        FlatBufferBuilder fbb = new FlatBufferBuilder(1024);
+
+        int name = fbb.createString("KerbyBackend");
+
+        KrbIdentity krbId = idendenties.get(0);
+        int princNameOff = fbb.createString(krbId.getPrincipalName());
+        int nameType = krbId.getPrincipal().getNameType().getValue();
+        int princOff = FbsPrincipalName.createFbsPrincipalName(fbb, nameType, princNameOff);
+        EncryptionKey encKey = krbId.getKeys().entrySet().iterator().next().getValue();
+        int keyValueOff = FbsEncryptionKey.createKeyValueVector(fbb, encKey.getKeyData());
+        int encKeyOff = FbsEncryptionKey.createFbsEncryptionKey(fbb,
+                encKey.getKeyType().getValue(), keyValueOff);
+        int keysOff = FbsKrbIdentity.createKeysVector(fbb, new int[]{encKeyOff});
+        int identityOff = FbsKrbIdentity.createFbsKrbIdentity(fbb, princOff, 1, 1, false, keysOff);
+        int idsOff = FbsKerby.createIdentitiesVector(fbb, new int[]{identityOff});
+
+        FbsKerby.startFbsKerby(fbb);
+        FbsKerby.addName(fbb, name);
+        FbsKerby.addIdentities(fbb, idsOff);
+        int kerbyOff = FbsKerby.endFbsKerby(fbb);
+        FbsKerby.finishFbsKerbyBuffer(fbb, kerbyOff);
+
+        ByteBuffer dataBuffer = fbb.dataBuffer().duplicate();
+
+        FbsKerby fbsKerby2 = FbsKerby.getRootAsFbsKerby(dataBuffer);
+        String kerbyName = fbsKerby2.name();
+        FbsKrbIdentity krbId2 = fbsKerby2.identities(0);
+        String princName2 = krbId2.principal().nameString();
+        return;
+    }
+}
diff --git a/kerby-backend/flatbuffers-backend/src/test/monsterdata_test.mon b/kerby-backend/flatbuffers-backend/src/test/monsterdata_test.mon
new file mode 100644
index 0000000..0505aee
--- /dev/null
+++ b/kerby-backend/flatbuffers-backend/src/test/monsterdata_test.mon
Binary files differ
diff --git a/kerby-backend/pom.xml b/kerby-backend/pom.xml
index 1305721..d49f40b 100644
--- a/kerby-backend/pom.xml
+++ b/kerby-backend/pom.xml
@@ -30,6 +30,7 @@
     <module>mavibot-backend</module>
     <module>json-backend</module>
     <module>zookeeper-backend</module>
+    <module>flatbuffers-backend</module>
   </modules>
 
   <dependencies>
diff --git a/monsterdata_java_wire.mon b/monsterdata_java_wire.mon
new file mode 100644
index 0000000..24602bc
--- /dev/null
+++ b/monsterdata_java_wire.mon
Binary files differ