diff --git a/docs/tutorials/quickstart-app-auth.md b/docs/tutorials/quickstart-app-auth.md
new file mode 100644
index 0000000000..fea1d7085a
--- /dev/null
+++ b/docs/tutorials/quickstart-app-auth.md
@@ -0,0 +1,199 @@
+---
+id: quickstart-app-auth
+title: Monorepo App Setup With Authentication
+---
+
+###### September 15th 2020 - @backstage/create-app - v0.1.1-alpha.21
+
+
+
+> This document takes you through setting up a backstage app that runs in your
+> own environment. It starts with a skeleton install and verifying of the
+> monorepo's functionality. Next, GitHub authentication is added and tested.
+>
+> This document assumes you have NodeJS 12 active along with Yarn. Please note,
+> that at the time of this writing, the current version is 0.1.1-alpha.21. This
+> guide can still be used with future versions, just, verify as you go. If you
+> run into issues, you can compare your setup with mine here >
+> [simple-backstage-app](https://github.com/johnson-jesse/simple-backstage-app).
+
+# The Skeleton Application
+
+From the terminal:
+
+1. Create a (monorepo) application: `npx @backstage/create-app`
+1. Enter an `id` for your new app like `mybiz-backstage` I went with
+ `simple-backstage-app`
+1. Choose `SQLite` as your database. This is the quickest way to get started as
+ PostgreSQL requires additional setup not covered here.
+1. Start your backend: `yarn --cwd packages/backend start`
+
+```zsh
+# You should see positive verbiage in your terminal output
+2020-09-11T22:20:26.712Z backstage info Listening on :7000
+```
+
+5. Finally, start the frontend. Open a new terminal window and from the root of
+ your project, run: `yarn start`
+
+```zsh
+# You should see positive verbiage in your terminal output
+ℹ 「wds」: Project is running at http://localhost:3000/
+```
+
+Once the app compiles, a browser window should have popped with your stand alone
+application loaded at `localhost:3000`. This could take a couple minutes.
+
+```zsh
+# You should see positive verbiage in your terminal output
+ℹℹ 「wdm」: Compiled successfully.
+```
+
+Since there is no auth currently configured, you are automatically entered as a
+guest. Let's fix that now and add auth.
+
+# The Auth Configuration
+
+1. Open `app-config.yaml` and change it as follows
+
+_from:_
+
+```yaml
+auth:
+ providers: {}
+```
+
+_to:_
+
+```yaml
+auth:
+ providers:
+ github:
+ development:
+ clientId:
+ $secret:
+ env: AUTH_GITHUB_CLIENT_ID
+ clientSecret:
+ $secret:
+ env: AUTH_GITHUB_CLIENT_SECRET
+ ## uncomment the following three lines if using enterprise
+ # enterpriseInstanceUrl:
+ # $secret:
+ # env: AUTH_GITHUB_ENTERPRISE_INSTANCE_URL
+```
+
+2. Set environment variables in whatever fashion is easiest for you. I chose to
+ add mine to my `.zshrc` profile.
+
+```zsh
+# For macOS Catalina & Z Shell
+# ------ simple-backstage-app GitHub
+export AUTH_GITHUB_CLIENT_ID=xxx
+export AUTH_GITHUB_CLIENT_SECRET=xxx
+# export AUTH_GITHUB_ENTERPRISE_INSTANCE_URL=https://github.{MY_BIZ}.com
+```
+
+3. And of course I need to source that file.
+
+```zsh
+# Loading the new variables
+% source ~/.zshrc
+
+# Any other currently opened terminals need to be restarted to pick up the new values
+# verify your setup by running env
+% env
+# should output something like
+> ...
+> AUTH_GITHUB_CLIENT_ID=xxx
+> AUTH_GITHUB_CLIENT_SECRET=xxx
+> ...
+```
+
+4. The values to replace `xxx` above come from your oauth app setup.
+
+```
+> Log into http://github.com
+> Navigate to (Settings > Developer Settings > OAuth Apps > New OAuth App)[https://github.com/settings/applications/new]
+> Set Homepage URL = http://localhost:3000
+> Set Callback URL = http://localhost:7000/auth/github
+> Click [Register application]
+> On the next page, copy and paste your new Client ID and Client Secret to the environment variables above, `AUTH_GITHUB_CLIENT_ID` & `AUTH_GITHUB_CLIENT_SECRET`
+> Don't forget to `source` that profile file again if necessary.
+```
+
+5. Open and change _root > packages > app > src >_`App.tsx` as follows
+
+```tsx
+// Add the following imports to the existing list from core
+import { githubAuthApiRef, SignInPage } from '@backstage/core';
+```
+
+6. In the same file, change the createApp function as follows
+
+```tsx
+const app = createApp({
+ apis,
+ plugins: Object.values(plugins),
+ components: {
+ SignInPage: props => {
+ return (
+
+ );
+ },
+ },
+});
+```
+
+6. Open and change _root > packages > app > src >_ `apis.ts` as follows
+
+```ts
+// Add the following imports to the existing list from core
+import { githubAuthApiRef, GithubAuth } from '@backstage/core';
+```
+
+7. In the same file, change the builder block for oauthRequestApiRef as follows
+
+_from:_
+
+```ts
+builder.add(oauthRequestApiRef, new OAuthRequestManager());
+```
+
+_to:_
+
+```ts
+const oauthRequestApi = builder.add(
+ oauthRequestApiRef,
+ new OAuthRequestManager(),
+);
+
+builder.add(
+ githubAuthApiRef,
+ GithubAuth.create({
+ discoveryApi,
+ oauthRequestApi,
+ }),
+);
+```
+
+> Start the backend and frontend as before. When the browser loads, you should
+> be presented with a login page for GitHub. Login as usual with your GitHub
+> account. If this is your first time, you will be asked to authorize and then
+> are redirected to the catalog page if all is well.
+
+# Where to go from here
+
+> You're probably eager to write your first custom plugin. Follow this next
+> tutorial for an in-depth look at a custom GitHub repository browser plugin.
+> [Adding Custom Plugin to Existing Monorepo App](quickstart-app-plugin.md).
diff --git a/docs/tutorials/quickstart-app-plugin.md b/docs/tutorials/quickstart-app-plugin.md
new file mode 100644
index 0000000000..28efb2a007
--- /dev/null
+++ b/docs/tutorials/quickstart-app-plugin.md
@@ -0,0 +1,487 @@
+---
+id: quickstart-app-plugin
+title: Adding Custom Plugin to Existing Monorepo App
+---
+
+###### September 15th 2020 - v0.1.1-alpha.21
+
+
+
+> This document takes you through setting up a new plugin for your existing
+> monorepo with a _GitHub provider already setup_. If you don't have either of
+> those, you can clone
+> [simple-backstage-app](https://github.com/johnson-jesse/simple-backstage-app)
+> which this document builds on.
+>
+> This document does not cover authoring a plugin for sharing with the Backstage
+> community. That will have to be a later discussion.
+>
+> We start with a skeleton plugin install. And after verifying its
+> functionality, extend the Sidebar to make our life easy. Finally, we add
+> custom code to display GitHub repository information.
+>
+> This document assumes you have NodeJS 12 active along with Yarn. Please note,
+> that at the time of this writing, the current version is 0.1.1-alpha.21. This
+> guide can still be used with future versions, just, verify as you go. If you
+> run into issues, you can compare your setup with mine here >
+> [simple-backstage-app-plugin](https://github.com/johnson-jesse/simple-backstage-app-plugin).
+
+# The Skeleton Plugin
+
+1. Start by using the built in creator. From the terminal and root of your
+ project run: `yarn create-plugin`
+1. Enter a plugin ID. I used `github-playground`
+1. When the process finishes, let's start the backend:
+ `yarn --cwd packages/backend start`
+1. If you see errors starting, refer to
+ [Auth Configuration](https://github.com/johnson-jesse/simple-backstage-app/blob/master/README.md#the-auth-configuration)
+ for more information on environment variables.
+1. And now the frontend, from a new terminal window and the root of your
+ project: `yarn start`
+1. As usual, a browser window should popup loading the App.
+1. Now manually navigate to our plugin page from your browser:
+ `http://localhost:3000/github-playground`
+1. You should see successful verbiage for this endpoint,
+ `Welcome to github-playground!`
+
+# The Shortcut
+
+Let's add a shortcut.
+
+1. Open and modify `root: packages > app > src > sidebar.tsx` with the
+ following:
+
+```tsx
+import GitHubIcon from '@material-ui/icons/GitHub';
+...
+
+```
+
+Simple! The App will reload with your changes automatically. You should now see
+a github icon displayed in the sidebar. Clicking that will link to our new
+plugin. And now, the API fun begins.
+
+# The Identity
+
+Our first modification will be to extract information from the Identity API.
+
+1. Start by opening
+ `root: plugins > github-playground > src > components > ExampleComponent > ExampleComponent.tsx`
+1. Add two new imports
+
+```tsx
+// Add identityApiRef to the list of imported from core
+import { identityApiRef } from '@backstage/core';
+import { useApi } from '@backstage/core-api';
+```
+
+3. Adjust the ExampleComponent from inline to block
+
+_from inline:_
+
+```tsx
+const ExampleComponent: FC<{}> = () => ( ... )
+```
+
+_to block:_
+
+```tsx
+const ExampleComponent: FC<{}> = () => {
+
+ return (
+ ...
+ )
+}
+```
+
+4. Now add our hook and const data before the return statement
+
+```tsx
+// our API hook
+const identityApi = useApi(identityApiRef);
+
+// data to use
+const userId = identityApi.getUserId();
+const profile = identityApi.getProfile();
+```
+
+5. Finally, update the InfoCard's jsx to use our new data
+
+```tsx
+
+
+ {`${profile.displayName} | ${profile.email}`}
+
+
+```
+
+If everything is saved, you should see your name, id, and email on the
+github-playground page. Our data accessed is synchronous. So we just grab and
+go.
+
+6. Here is the entire file for reference
+Complete ExampleComponent.tsx
+
+
+```tsx
+import React, { FC } from 'react';
+import { Typography, Grid } from '@material-ui/core';
+import {
+ InfoCard,
+ Header,
+ Page,
+ pageTheme,
+ Content,
+ ContentHeader,
+ HeaderLabel,
+ SupportButton,
+ identityApiRef,
+} from '@backstage/core';
+import { useApi } from '@backstage/core-api';
+import ExampleFetchComponent from '../ExampleFetchComponent';
+
+const ExampleComponent: FC<{}> = () => {
+ const identityApi = useApi(identityApiRef);
+ const userId = identityApi.getUserId();
+ const profile = identityApi.getProfile();
+
+ return (
+
+
+
+
+ A description of your plugin goes here.
+
+
+
+
+
+ {`${profile.displayName} | ${profile.email}`}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ExampleComponent;
+```
+
+
+
+
+# The Wipe
+
+The last file we will touch is ExampleFetchComponent. Because of the number of
+changes, let's start by wiping this component clean.
+
+1. Start by opening
+ `root: plugins > github-playground > src > components > ExampleFetchComponent > ExampleFetchComponent.tsx`
+1. Replace everyting in the file with the following:
+
+```tsx
+import React, { FC } from 'react';
+import { useAsync } from 'react-use';
+import Alert from '@material-ui/lab/Alert';
+import {
+ Table,
+ TableColumn,
+ Progress,
+ githubAuthApiRef,
+} from '@backstage/core';
+import { useApi } from '@backstage/core-api';
+import { graphql } from '@octokit/graphql';
+
+const ExampleFetchComponent: FC<{}> = () => {
+ return
Nothing to see yet
;
+};
+
+export default ExampleFetchComponent;
+```
+
+3. Save that and ensure you see no errors. Comment out the unused imports if
+ your linter gets in the way.
+
+###### We will add a lot to this file for the sake of ease. Please don't do this in productional code!
+
+# The Graph Model
+
+GitHub has a graphql API available for interacting. Let's start by adding our
+basic repository query
+
+1. Add the query const statement outside ExampleFetchComponent
+
+```tsx
+const query = `{
+ viewer {
+ repositories(first: 100) {
+ totalCount
+ nodes {
+ name
+ createdAt
+ description
+ diskUsage
+ isFork
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+ }
+}`;
+```
+
+2. Using this structure as a guide, we will break our query into type parts
+3. Add the following outside of ExampleFetchComponent
+
+```tsx
+type Node = {
+ name: string;
+ createdAt: string;
+ description: string;
+ diskUsage: number;
+ isFork: boolean;
+};
+
+type Viewer = {
+ repositories: {
+ totalCount: number;
+ nodes: Node[];
+ pageInfo: {
+ endCursor: string;
+ hasNextPage: boolean;
+ };
+ };
+};
+```
+
+# The Tabel Model
+
+Using Backstage's own component library, let's define a custom table. This
+component will get used if we have data to display.
+
+1. Add the following outside of ExampleFetchComponent
+
+```tsx
+type DenseTableProps = {
+ viewer: Viewer;
+};
+
+export const DenseTable: FC = ({ viewer }) => {
+ const columns: TableColumn[] = [
+ { title: 'Name', field: 'name' },
+ { title: 'Created', field: 'createdAt' },
+ { title: 'Description', field: 'description' },
+ { title: 'Disk Usage', field: 'diskUsage' },
+ { title: 'Fork', field: 'isFork' },
+ ];
+
+ return (
+
+ );
+};
+```
+
+# The Fetch
+
+We're ready to flush out our fetch component
+
+1. Add our api hook inside ExampleFetchComponent
+
+```tsx
+const auth = useApi(githubAuthApiRef);
+```
+
+2. The access token we need to make our GitHub request and the request itself is
+ obtained in an asynchronous manner.
+3. Add the useAsync block inside the ExampleFetchComponent
+
+```tsx
+const { value, loading, error } = useAsync(async (): Promise => {
+ const token = await auth.getAccessToken();
+
+ const gqlEndpoint = graphql.defaults({
+ // Uncomment baseUrl if using enterprise
+ // baseUrl: 'https://github.MY-BIZ.com/api',
+ headers: {
+ authorization: `token ${token}`,
+ },
+ });
+ const { viewer } = await gqlEndpoint(query);
+ return viewer;
+}, []);
+```
+
+4. The resolved data is conventiently destructured with value containing our
+ Viewer type. loading as a boolean, self explainatory. And error which is
+ present only if necessary. So let's use those as the first 3 of 4 multi
+ return statements.
+5. Add the _if return_ blocks below our async block
+
+```tsx
+if (loading) return ;
+if (error) return {error.message};
+if (value && value.repositories) return ;
+```
+
+6. The third line here utilizes our custom table accepting our Viewer type.
+7. Finally, we add our _else return_ block to catch any other scenarios.
+
+```tsx
+return (
+
+);
+```
+
+8. After saving that, and given we don't have any errors, you should see a table
+ with basic information on your repositories.
+9. Here is the entire file for reference
+Complete ExampleFetchComponent.tsx
+
+
+```tsx
+import React, { FC } from 'react';
+import { useAsync } from 'react-use';
+import Alert from '@material-ui/lab/Alert';
+import {
+ Table,
+ TableColumn,
+ Progress,
+ githubAuthApiRef,
+} from '@backstage/core';
+import { useApi } from '@backstage/core-api';
+import { graphql } from '@octokit/graphql';
+
+const query = `{
+viewer {
+ repositories(first: 100) {
+ totalCount
+ nodes {
+ name
+ createdAt
+ description
+ diskUsage
+ isFork
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
+ }
+ }
+}
+}`;
+
+type Node = {
+ name: string;
+ createdAt: string;
+ description: string;
+ diskUsage: number;
+ isFork: boolean;
+};
+
+type Viewer = {
+ repositories: {
+ totalCount: number;
+ nodes: Node[];
+ pageInfo: {
+ endCursor: string;
+ hasNextPage: boolean;
+ };
+ };
+};
+
+type DenseTableProps = {
+ viewer: Viewer;
+};
+
+export const DenseTable: FC = ({ viewer }) => {
+ const columns: TableColumn[] = [
+ { title: 'Name', field: 'name' },
+ { title: 'Created', field: 'createdAt' },
+ { title: 'Description', field: 'description' },
+ { title: 'Disk Usage', field: 'diskUsage' },
+ { title: 'Fork', field: 'isFork' },
+ ];
+
+ return (
+
+ );
+};
+
+const ExampleFetchComponent: FC<{}> = () => {
+ const auth = useApi(githubAuthApiRef);
+
+ const { value, loading, error } = useAsync(async (): Promise => {
+ const token = await auth.getAccessToken();
+
+ const gqlEndpoint = graphql.defaults({
+ // Uncomment baseUrl if using enterprise
+ // baseUrl: 'https://github.MY-BIZ.com/api',
+ headers: {
+ authorization: `token ${token}`,
+ },
+ });
+ const { viewer } = await gqlEndpoint(query);
+ return viewer;
+ }, []);
+
+ if (loading) return ;
+ if (error) return {error.message};
+ if (value && value.repositories) return ;
+
+ return (
+
+ );
+};
+
+export default ExampleFetchComponent;
+```
+
+
+
+
+10. We finished! If there are no errors, you should see your own GitHub
+ repoistory information displayed in a basic table. If you run into issues,
+ you can compare the repo that backs this documdnt,
+ [simple-backstage-app-plugin](https://github.com/johnson-jesse/simple-backstage-app-plugin)
+
+# Where to go from here
+
+> Break apart ExampleFetchComponent into smaller logical parts contained in
+> their own files. Rename your components to something other than ExampleXxx.
+>
+> You might be real proud of a plugin you develop. Follow this next tutorial for
+> an in-depth look at publishing and including that for the entire Backstage
+> community. [TODO](#).
diff --git a/microsite/sidebars.json b/microsite/sidebars.json
index f7aa0630ef..aac524c538 100644
--- a/microsite/sidebars.json
+++ b/microsite/sidebars.json
@@ -143,7 +143,11 @@
"ids": ["api/backend"]
}
],
- "Tutorials": ["tutorials/journey"],
+ "Tutorials": [
+ "tutorials/journey",
+ "tutorials/quickstart-app-auth",
+ "tutorials/quickstart-app-plugin"
+ ],
"Architecture Decision Records (ADRs)": [
"architecture-decisions/adrs-overview",
"architecture-decisions/adrs-adr001",