diff --git a/config.json b/config.json
index 1ce30691717b2ffefecfab768b21f2ec0b62a505..5290951786562c654ff7f038aecc484e3b2662ab 100644
--- a/config.json
+++ b/config.json
@@ -1,4 +1,5 @@
 {
     "homeserver": "http://localhost:8008",
-    "auto_join_room": "!KiuRShFqxJLSoshNKa:localhost:8008"
-}
\ No newline at end of file
+    "auto_join_room": "!KiuRShFqxJLSoshNKa:localhost:8008",
+    "username_prefix": "testcorp"
+}
diff --git a/src/random.ts b/src/random.ts
index b3f2412896056d9df0ddbd9d0ff5fb8136e05d1d..1b668e8a3e3a2ff728e94aec88e03cd19035bc97 100644
--- a/src/random.ts
+++ b/src/random.ts
@@ -1,13 +1,18 @@
-// todo: do we need something better than this?
-// todo: usernames can't start with _
-// todo: lookup grammar for mxids
-
-export function generateRandomString(length: number): string {
+function generateRandomString(length: number, allowedCharacters: string): string {
     let result = "";
-    const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
-    var charactersLength = characters.length;
+    const l = allowedCharacters.length;
     for (let i = 0; i < length; i++) {
-        result += characters.charAt(Math.floor(Math.random() * charactersLength));
+        result += allowedCharacters.charAt(Math.floor(Math.random() * l));
     }
     return result;
 }
+
+export function generatePassword(length: number) {
+    const characters = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+    return generateRandomString(length, characters);
+}
+
+export function generateUsername(length: number) {
+    const characters = 'abcdefghijklmnopqrstuvwxyz0123456789_-.=/';
+    return generateRandomString(length, characters);
+}
diff --git a/src/types/IChatterboxConfig.ts b/src/types/IChatterboxConfig.ts
index 80f97222746a07ed24b8d781e4ae17eb1c1d733c..bf0bd8e302333af9955225b500d0b559094fa989 100644
--- a/src/types/IChatterboxConfig.ts
+++ b/src/types/IChatterboxConfig.ts
@@ -1,4 +1,5 @@
 export interface IChatterboxConfig {
 	homeserver: string;
 	auto_join_room: string;
-}
\ No newline at end of file
+    username_prefix: string;
+}
diff --git a/src/viewmodels/AccountSetupViewModel.ts b/src/viewmodels/AccountSetupViewModel.ts
index 3e2bc30cdf6afbbf3cb70b2ee93266f68fb130fb..03bb2567d6170bae788424d5788f61c216b7d564 100644
--- a/src/viewmodels/AccountSetupViewModel.ts
+++ b/src/viewmodels/AccountSetupViewModel.ts
@@ -1,6 +1,6 @@
 import { ViewModel, Client, LoadStatus } from "hydrogen-view-sdk";
 import { IChatterboxConfig } from "../types/IChatterboxConfig";
-import { generateRandomString } from "../random";
+import { generatePassword, generateUsername } from "../random";
 import "hydrogen-view-sdk/style.css";
 
 
@@ -9,6 +9,7 @@ export class AccountSetupViewModel extends ViewModel {
     private _client: typeof Client;
     private _termsStage?: any;
     private _password: string;
+    private _username: string;
 
     constructor(options) {
         super(options);
@@ -18,8 +19,9 @@ export class AccountSetupViewModel extends ViewModel {
     }
 
     private async _startRegistration(): Promise<void> {
-        this._password = generateRandomString(10);
-        let stage = await this._client.startRegistration(this._homeserver, null, this._password, "Chatterbox");
+        this._password = generatePassword(10);
+        this._username = `${this._config.username_prefix}-${generateUsername(10)}`;
+        let stage = await this._client.startRegistration(this._homeserver, this._username, this._password, "Chatterbox");
         if (stage.type === "m.login.terms") {
             this._termsStage = stage;
             this.emitChange("termsStage");
@@ -32,7 +34,7 @@ export class AccountSetupViewModel extends ViewModel {
             stage = await stage.complete();
         }
         // stage is username when registration is completed
-        const loginPromise = this.login(stage, this._password);
+        const loginPromise = this.login(this._username, this._password);
         this.navigation.push("timeline", loginPromise);
     }