-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path782523bc.50d7e72e.js
1 lines (1 loc) · 59.5 KB
/
782523bc.50d7e72e.js
1
(window.webpackJsonp=window.webpackJsonp||[]).push([[19],{111:function(e,n,t){"use strict";t.d(n,"a",(function(){return p})),t.d(n,"b",(function(){return g}));var a=t(0),r=t.n(a);function o(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function i(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function s(e){for(var n=1;n<arguments.length;n++){var t=null!=arguments[n]?arguments[n]:{};n%2?i(Object(t),!0).forEach((function(n){o(e,n,t[n])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(t)):i(Object(t)).forEach((function(n){Object.defineProperty(e,n,Object.getOwnPropertyDescriptor(t,n))}))}return e}function c(e,n){if(null==e)return{};var t,a,r=function(e,n){if(null==e)return{};var t,a,r={},o=Object.keys(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a<o.length;a++)t=o[a],n.indexOf(t)>=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=r.a.createContext({}),u=function(e){var n=r.a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):s(s({},n),e)),t},p=function(e){var n=u(e.components);return r.a.createElement(l.Provider,{value:n},e.children)},d={inlineCode:"code",wrapper:function(e){var n=e.children;return r.a.createElement(r.a.Fragment,{},n)}},m=r.a.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,i=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),p=u(t),m=a,g=p["".concat(i,".").concat(m)]||p[m]||d[m]||o;return t?r.a.createElement(g,s(s({ref:n},l),{},{components:t})):r.a.createElement(g,s({ref:n},l))}));function g(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var s={};for(var c in n)hasOwnProperty.call(n,c)&&(s[c]=n[c]);s.originalType=e,s.mdxType="string"==typeof e?e:a,i[1]=s;for(var l=2;l<o;l++)i[l]=t[l];return r.a.createElement.apply(null,i)}return r.a.createElement.apply(null,t)}m.displayName="MDXCreateElement"},112:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/patreon-15b4e66595efdb2e079faf18b89cff7c.png"},116:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/01-a23cc15b10aa8903a2768742f2d5f639.png"},117:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/02-d8f056a9ee77817d5fa34ed27b8a9ded.png"},120:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/03-99e9f84b954c87f14c5b1c2a2fc7beb5.png"},121:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/04-b7fa82403420155f5bc0c2e2b713251f.png"},122:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/05-1c1a60851841e4476b56c3edf139208b.png"},123:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/06-e6c67e52061de238f27f3c609644f4b9.png"},124:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/07-8a3ce13813e6679ceb6d32560f619235.png"},129:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/08-c284e2b885bb0393ec87b2e5af025826.png"},130:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/09-e3185a977d8228e9551c978b4032cfeb.png"},134:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/00-1339b6b03bac7ae4b5b7308a8055bf6b.gif"},135:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth02-a6bbe130e5a203fb1094bf10025c251c.png"},136:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth03-c26b5e57e8cf643cec8fddc2a31ad7d1.png"},137:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/10-4f1052b7e740229f97d3918602f76c7b.png"},138:function(e,n,t){"use strict";t.r(n),n.default="data:image/png;base64,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"},158:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-04-350f5fb9ab327f3254e044f289409cab.png"},159:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/12-d15746e9380cc15500789c8f73ffff3e.png"},247:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-05-7560fb43a390f71c28d251982e07b5c1.png"},248:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-06-bb4949de0664d1f2ad37d4ff03478c6e.png"},249:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-07-804ff884f8fd1092001cff54a924efae.png"},250:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-08-723a1885ae9a48e77b74d7cfd3bc186a.png"},251:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/13-feb15ab473e5e3b939d58d822fcfac81.png"},252:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-09-f99c7f22ab93676b45423d27e8172438.png"},253:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-10-71a307372cb708b20ea70110dca5cd99.png"},254:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/14-032e45897af97099b0cc5da21066f06c.png"},255:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/auth1-11-9b4792e3ad9c8cec5bcca61b8db3de34.png"},256:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/15-453822ff14bf66563a3754574047d0ed.png"},257:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/16-38364af3bf7c51d4456f2fbbdccd12e9.png"},258:function(e,n,t){"use strict";t.r(n),n.default=t.p+"assets/images/17-567da57df82c396df3ed6c31c243d666.png"},88:function(e,n,t){"use strict";t.r(n),t.d(n,"frontMatter",(function(){return i})),t.d(n,"metadata",(function(){return s})),t.d(n,"rightToc",(function(){return c})),t.d(n,"default",(function(){return u}));var a=t(3),r=t(8),o=(t(0),t(111)),i={id:"auth1-02",title:"Authentication",sidebar_label:"Custom setup"},s={unversionedId:"auth1-02",id:"auth1-02",isDocsHomePage:!1,title:"Authentication",description:"Firstly, the standard UI from Amplify does not always meet customer UX requirements",source:"@site/docs/auth1.02.md",slug:"/auth1-02",permalink:"/docs/auth1-02",editUrl:"https://github.com/facebook/docusaurus/edit/master/website/docs/auth1.02.md",version:"current",sidebar_label:"Custom setup",sidebar:"someSidebar",previous:{title:"Authentication",permalink:"/docs/auth1-01"},next:{title:"AWS Amplify",permalink:"/docs/amplify-00"}},c=[{value:"Clone the repository",id:"clone-the-repository",children:[]},{value:"Initializing AWS Amplify in a React Native Project",id:"initializing-aws-amplify-in-a-react-native-project",children:[]},{value:"Connect authentication plugin",id:"connect-authentication-plugin",children:[]},{value:"Connect AWS Amplify to React Native",id:"connect-aws-amplify-to-react-native",children:[]},{value:"Add navigation",id:"add-navigation",children:[]},{value:"react-native-keychain",id:"react-native-keychain",children:[]},{value:"AppNavigator",id:"appnavigator",children:[]},{value:"Hello screen",id:"hello-screen",children:[]},{value:"SignUp screen",id:"signup-screen",children:[]},{value:"ConfirmSignUp screen",id:"confirmsignup-screen",children:[]},{value:"ResendSignUp",id:"resendsignup",children:[]},{value:"User screen",id:"user-screen",children:[]},{value:"SignIn screen",id:"signin-screen",children:[]},{value:"Forgot password screen",id:"forgot-password-screen",children:[]},{value:"Forgot password submit",id:"forgot-password-submit",children:[]},{value:"Linking screens",id:"linking-screens",children:[]},{value:"Udpate AppNavigator",id:"udpate-appnavigator",children:[]},{value:"Debug",id:"debug",children:[]},{value:"Done \u2705",id:"done-",children:[]}],l={rightToc:c};function u(e){var n=e.components,i=Object(r.a)(e,["components"]);return Object(o.b)("wrapper",Object(a.a)({},l,i,{components:n,mdxType:"MDXLayout"}),Object(o.b)("p",null,"Firstly, the standard UI from Amplify does not always meet customer UX requirements"),Object(o.b)("p",null,"Secondly, in the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#managing-security-tokens"}),"official documentation")," of Amplify it is stated that:"),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"Data is stored unencrypted when using standard storage adapters (localStorage in the browser and AsyncStorage on React Native). Amplify gives you the option to use your own storage object to persist data. With this, you could write a thin wrapper around libraries like:\nreact-native-keychain\nreact-native-secure-storage\nExpo\u2019s secure store")),Object(o.b)("p",null,"This means that the authentication data is stored in an unencrypted form, and this is a risk\n\ud83d\udd77 of information security with possible negative consequences \ud83d\udd78."),Object(o.b)("p",null,"Source code for this part is available on ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://github.com/fullstackserverless/auth/tree/part2"}),"GitHub"),"."),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://youtu.be/QMObthDaewQ"}),Object(o.b)("img",{alt:"AWS Amplify",src:t(134).default}))),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step01",src:t(116).default})),Object(o.b)("h2",{id:"clone-the-repository"},"Clone the repository"),Object(o.b)("p",null,"Install the repository with the pre-installed ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://fullstackserverless.github.io/docs/unicorn00"}),"UI Kit")),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"git clone https://github.com/fullstackserverless/auth.git\n")),Object(o.b)("p",null,"Go to the project folder"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"cd auth\n")),Object(o.b)("p",null,"Install dependencies"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"yarn")),Object(o.b)("p",null,"or"),Object(o.b)("p",null,Object(o.b)("inlineCode",{parentName:"p"},"npm install")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step02",src:t(117).default})),Object(o.b)("h2",{id:"initializing-aws-amplify-in-a-react-native-project"},"Initializing AWS Amplify in a React Native Project"),Object(o.b)("p",null,"Initialize our AWS Amplify project in the root directory."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"amplify init\n")),Object(o.b)("p",null,"Answer these questions:"),Object(o.b)("p",null,Object(o.b)("img",{alt:"amplify init",src:t(135).default})),Object(o.b)("p",null,"The project successfully initialized \ud83d\ude80"),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step03",src:t(120).default})),Object(o.b)("h2",{id:"connect-authentication-plugin"},"Connect authentication plugin"),Object(o.b)("p",null,"Now that the application is in the cloud, you can add some features, such as allowing users to register with our application and log in."),Object(o.b)("p",null,"Use command:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"amplify add auth\n")),Object(o.b)("p",null,"Connect the authentication function. Select the default configuration. This adds auth resource configurations locally to your ampify/backend/auth directory"),Object(o.b)("div",{class:"alert alert--info",role:"alert"},"\ud83d\udccc Select the profile we want to use. default. Enter and how users will log in. Email (write off money for SMS)."),Object(o.b)("p",null,Object(o.b)("img",{alt:"amplify init",src:t(136).default})),Object(o.b)("p",null,"Submit changes to the cloud \ud83d\udcad"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"amplify push\n")),Object(o.b)("p",null,"\u2714 All resources are updated in the cloud"),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step04",src:t(121).default})),Object(o.b)("h2",{id:"connect-aws-amplify-to-react-native"},"Connect AWS Amplify to React Native"),Object(o.b)("p",null,"Details can be found in ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws-amplify.github.io/docs/js/react"}),"this")," instruction \ud83d\udcc3.In short, you can add these dependencies below to connect AWS Amplify:"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn add aws-amplify @aws-amplify/core aws-amplify-react-native amazon-cognito-identity-js @react-native-community/netinfo\n")),Object(o.b)("p",null,"After installation, make sure to go to the ios folder and set the pods"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"cd ios && pod install && cd ..\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step05",src:t(122).default})),Object(o.b)("h2",{id:"add-navigation"},"Add navigation"),Object(o.b)("p",null,"install react-navigation v5, based on this instruction ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://reactnavigation.org/docs/getting-started/"}),"here"),"\n(at the time of writing this article this is latest version of navigation)"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn add react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view @react-navigation/stack\n")),Object(o.b)("p",null,"Add pods for iOS"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"cd ios && pod install && cd ..\n")),Object(o.b)("div",{class:"alert alert--info",role:"alert"},"\ud83d\udccc I recommend to launch the application for iOS and Android, after each installation, in order to avoid searching for the library because of which the application crashes."),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step06",src:t(123).default})),Object(o.b)("h2",{id:"react-native-keychain"},"react-native-keychain"),Object(o.b)("p",null,"Add react-native-keychain - this is a secure keystore library for React Native."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"yarn add react-native-keychain\n")),Object(o.b)("p",null,"Add pods for iOS"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-bash"}),"cd ios && pod install && cd ..\n")),Object(o.b)("p",null,"According to ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://aws-amplify.github.io/docs/js/authentication#managing-security-tokens"}),"official documentation:")),Object(o.b)("blockquote",null,Object(o.b)("p",{parentName:"blockquote"},"When using authentication with AWS Amplify, you don\u2019t have to update Amazon Cognito tokens manually. Tokens are automatically updated by the library when necessary. Security tokens, such as IdToken or AccessToken, are stored in localStorage for the browser and in AsyncStorage for React Native. If you want to store these tokens in a more secure place or use Amplify on the server side, you can provide your own storage object for storing these tokens.")),Object(o.b)("p",null,"configure src/index.tsx"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { ReactElement } from 'react'\nimport Amplify from '@aws-amplify/core'\nimport * as Keychain from 'react-native-keychain'\nimport { useColorScheme } from 'react-native-appearance'\nimport ThemeProvider from './ThemeProvider'\nimport AppNavigator from './AppNavigator'\nimport awsconfig from '../aws-exports'\n\nconst DarkTheme = {\n dark: true,\n colors: {\n primary: '#50E3C2',\n background: '#1D1E1F',\n card: '#1D1E1F',\n text: '#ffffff',\n border: '#ff06f4'\n }\n}\n\nconst LightTheme = {\n dark: false,\n colors: {\n primary: '#ff06f4',\n background: '#ffffff',\n card: '#1D1E1F',\n text: '#ffffff',\n border: '#ff06f4'\n }\n}\n\nconst MEMORY_KEY_PREFIX = '@MyStorage:'\nlet dataMemory: any = {}\nclass MyStorage {\n static syncPromise = null\n\n static setItem(key: string, value: string): boolean {\n Keychain.setGenericPassword(MEMORY_KEY_PREFIX + key, value)\n dataMemory[key] = value\n return dataMemory[key]\n }\n\n static getItem(key: string): boolean {\n return Object.prototype.hasOwnProperty.call(dataMemory, key) ? dataMemory[key] : undefined\n }\n\n static removeItem(key: string): boolean {\n Keychain.resetGenericPassword()\n return delete dataMemory[key]\n }\n\n static clear(): object {\n dataMemory = {}\n return dataMemory\n }\n}\n\nAmplify.configure({\n ...awsconfig,\n Analytics: {\n disabled: false\n },\n storage: MyStorage\n})\n\nconst App = (): ReactElement => {\n /**\n * Subscribe to color scheme changes with a hook\n */\n const scheme = useColorScheme()\n return (\n <>\n <ThemeProvider theme={scheme === 'dark' ? DarkTheme : LightTheme}>\n <AppNavigator />\n </ThemeProvider>\n </>\n )\n}\n\nexport default App\n")),Object(o.b)("p",null,"For client authorization AppSync supports API Keys, Amazon IAM credentials, Amazon Cognito User Pools, and 3rd party OIDC providers. This is inferred from the aws-exports.js file when you call Amplify.configure()."),Object(o.b)("p",null,"When using Authentication with AWS Amplify, you don\u2019t need to refresh Amazon Cognito tokens manually. The tokens are automatically refreshed by the library when necessary.\nSecurity Tokens like IdToken or AccessToken are stored in localStorage for the browser and in AsyncStorage for React Native. If you want to store those tokens in a more secure place or you are using Amplify in server side, then you can provide your own storage object to store those tokens."),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step07",src:t(124).default})),Object(o.b)("h2",{id:"appnavigator"},"AppNavigator"),Object(o.b)("p",null,"Create a navigation configuration file for our custom authentication src/AppNavigator.tsx\nAdd a welcome screen to it."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import * as React from 'react'\nimport { createStackNavigator } from '@react-navigation/stack'\nimport { Hello } from './screens/Authenticator'\n\nconst Stack = createStackNavigator()\n\nexport type RootStackParamList = {\n HELLO: undefined\n}\n\nconst AppNavigator = () => {\n return (\n <Stack.Navigator\n screenOptions={{\n headerShown: false\n }}\n initialRouteName=\"HELLO\"\n >\n <Stack.Screen name=\"HELLO\" component={Hello} />\n </Stack.Navigator>\n )\n}\n\nexport default AppNavigator\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step08",src:t(129).default})),Object(o.b)("h2",{id:"hello-screen"},"Hello screen"),Object(o.b)("p",null,"Create an entry point for our authentication screens src/screens/Authenticator/index.ts"),Object(o.b)("p",null,Object(o.b)("img",{alt:"Hello screen",src:t(158).default})),Object(o.b)("p",null,"To begin with, let's connect welcome screen"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"export * from './Hello'\n")),Object(o.b)("p",null,"After we create it src/screens/Authenticator/Hello/index.tsx"),Object(o.b)("p",null,"In the useEffect hook, we check for a user token, where in the case of true we go to the User screen, and in the case of false, we remain on this screen."),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useEffect, useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport * as Keychain from 'react-native-keychain'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { AppContainer, Button, Space, Txt } from '../../../components'\nimport { onScreen } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'HELLO'>\n\ntype HelloT = {\n navigation: ProfileScreenNavigationProp\n}\n\nconst Hello = ({ navigation }: HelloT): ReactElement => {\n const [loading, setLoading] = useState(false)\n useEffect(() => {\n setLoading(true)\n const key = async (): Promise<void> => {\n try {\n const credentials = await Keychain.getInternetCredentials('auth')\n\n if (credentials) {\n const { username, password } = credentials\n const user = await Auth.signIn(username, password)\n setLoading(false)\n user && onScreen('USER', navigation)()\n } else {\n setLoading(false)\n }\n } catch (err) {\n console.log('error', err) // eslint-disable-line\n setLoading(false)\n }\n }\n key()\n }, []) // eslint-disable-line\n return (\n <AppContainer loading={loading}>\n <Space height={80} />\n <Button title=\"Sign In\" onPress={onScreen('SIGN_IN', navigation)} />\n <Space height={10} />\n <Txt h6 title=\"or\" textStyle={{ alignSelf: 'center' }} />\n <Space height={15} />\n <Button title=\"Sign Up\" onPress={onScreen('SIGN_UP', navigation)} />\n </AppContainer>\n )\n}\n\nexport { Hello }\n")),Object(o.b)("p",null,"Put together all changes and meet the welcome screen."),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step09",src:t(130).default})),Object(o.b)("h2",{id:"signup-screen"},"SignUp screen"),Object(o.b)("p",null,"We create the registration screen SIGN_UP src/screens/Authenticator/SignUp/index.tsx, where for authentication we use the ",Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://docs.amplify.aws/lib/auth/emailpassword/q/platform/js#sign-up"}),"Auth.signUp")," method."),Object(o.b)("p",null,Object(o.b)("img",{alt:"SignUp",src:t(247).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport * as Keychain from 'react-native-keychain'\nimport { Formik } from 'formik'\nimport * as Yup from 'yup'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { AppContainer, Space, Button, Input, TextError } from '../../../components'\nimport { onScreen, goBack } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'SIGN_UP'>\n\ntype SignUpT = {\n navigation: ProfileScreenNavigationProp\n}\n\nconst SignUp = ({ navigation }: SignUpT): ReactElement => {\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n const _onPress = async (values: { email: string; password: string; passwordConfirmation: string }): Promise<void> => {\n const { email, password, passwordConfirmation } = values\n if (password !== passwordConfirmation) {\n setError('Passwords do not match!')\n } else {\n setLoading(true)\n setError('')\n try {\n const user = await Auth.signUp(email, password)\n await Keychain.setInternetCredentials('auth', email, password)\n user && onScreen('CONFIRM_SIGN_UP', navigation, { email, password })()\n setLoading(false)\n } catch (err) {\n setLoading(false)\n if (err.code === 'UserNotConfirmedException') {\n setError('Account not verified yet')\n } else if (err.code === 'PasswordResetRequiredException') {\n setError('Existing user found. Please reset your password')\n } else if (err.code === 'NotAuthorizedException') {\n setError('Forgot Password?')\n } else if (err.code === 'UserNotFoundException') {\n setError('User does not exist!')\n } else {\n setError(err.code)\n }\n }\n }\n }\n\n return (\n <>\n <AppContainer onPress={goBack(navigation)} title=\"Sign Up\" loading={loading}>\n <Formik\n initialValues={{ email: '', password: '', passwordConfirmation: '' }}\n onSubmit={(values): Promise<void> => _onPress(values)}\n validationSchema={Yup.object().shape({\n email: Yup.string()\n .email()\n .required(),\n password: Yup.string()\n .min(6)\n .required(),\n passwordConfirmation: Yup.string()\n .min(6)\n .required()\n })}\n >\n {({ values, handleChange, errors, setFieldTouched, touched, handleSubmit }): ReactElement => (\n <>\n <Input\n name=\"email\"\n value={values.email}\n onChangeText={handleChange('email')}\n onBlur={(): void => setFieldTouched('email')}\n placeholder=\"E-mail\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n />\n <Input\n name=\"password\"\n value={values.password}\n onChangeText={handleChange('password')}\n onBlur={(): void => setFieldTouched('password')}\n placeholder=\"Password\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n secureTextEntry\n />\n <Input\n name=\"passwordConfirmation\"\n value={values.passwordConfirmation}\n onChangeText={handleChange('passwordConfirmation')}\n onBlur={(): void => setFieldTouched('passwordConfirmation')}\n placeholder=\"Password confirm\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n secureTextEntry\n />\n <Space height={30} />\n {error !== '' && <TextError title={error} textStyle={{ alignSelf: 'center' }} />}\n <Button title=\"Sign Up\" onPress={handleSubmit} />\n </>\n )}\n </Formik>\n </AppContainer>\n </>\n )\n}\n\nexport { SignUp }\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step10",src:t(137).default})),Object(o.b)("h2",{id:"confirmsignup-screen"},"ConfirmSignUp screen"),Object(o.b)("p",null,"After a successful response from the server, we go to the confirmation screen and enter the code that came to our mail. To do this, create the screen CONFIRM_SIGN_UP src/screens/Authenticator/ConfirmSignUp/index.tsx"),Object(o.b)("p",null,Object(o.b)("img",{alt:"ConfirmSignUp",src:t(248).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"import React, { useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport { Formik } from 'formik'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { RouteProp } from '@react-navigation/native'\nimport * as Yup from 'yup'\nimport { AppContainer, Button, Space, ButtonLink, TextError, Input } from '../../../components'\nimport { onScreen, goBack } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'CONFIRM_SIGN_UP'>\ntype ProfileScreenRouteProp = RouteProp<RootStackParamList, 'CONFIRM_SIGN_UP'>\n\ntype ConfirmSignUpT = {\n navigation: ProfileScreenNavigationProp\n route: ProfileScreenRouteProp\n}\n\nconst ConfirmSignUp = ({ route, navigation }: ConfirmSignUpT): ReactElement => {\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n const _onPress = async (values: { code: string }): Promise<void> => {\n setLoading(true)\n setError('')\n try {\n const { code } = values\n const { email, password } = route.params\n await Auth.confirmSignUp(email, code, { forceAliasCreation: true })\n const user = await Auth.signIn(email, password)\n user && onScreen('USER', navigation)()\n setLoading(false)\n } catch (err) {\n setLoading(false)\n setError(err.message)\n if (err.code === 'UserNotConfirmedException') {\n setError('Account not verified yet')\n } else if (err.code === 'PasswordResetRequiredException') {\n setError('Existing user found. Please reset your password')\n } else if (err.code === 'NotAuthorizedException') {\n setError('Forgot Password?')\n } else if (err.code === 'UserNotFoundException') {\n setError('User does not exist!')\n }\n }\n }\n\n const _onResend = async (): Promise<void> => {\n try {\n const { email } = route.params\n await Auth.resendSignUp(email)\n } catch (err) {\n setError(err.message)\n }\n }\n\n return (\n <>\n <AppContainer title=\"Confirmation\" onPress={goBack(navigation)} loading={loading}>\n <Formik\n initialValues={{ code: '' }}\n onSubmit={(values): Promise<void> => _onPress(values)}\n validationSchema={Yup.object().shape({\n code: Yup.string().min(6).required()\n })}\n >\n {({ values, handleChange, errors, setFieldTouched, touched, handleSubmit }): ReactElement => (\n <>\n <Space height={180} />\n <Input\n name=\"code\"\n value={values.code}\n onChangeText={handleChange('code')}\n onBlur={(): void => setFieldTouched('code')}\n placeholder=\"Insert code\"\n touched={touched}\n errors={errors}\n />\n <ButtonLink title=\"Resend code?\" onPress={_onResend} textStyle={{ alignSelf: 'center' }} />\n {error !== 'Forgot Password?' && <TextError title={error} />}\n <Button title=\"Confirm\" onPress={handleSubmit} />\n <Space height={50} />\n </>\n )}\n </Formik>\n </AppContainer>\n </>\n )\n}\n\nexport { ConfirmSignUp }\n")),Object(o.b)("h2",{id:"resendsignup"},"ResendSignUp"),Object(o.b)("p",null,"If the code has not arrived, then we must provide the user with the opportunity to resend the code.\nTo do this, we put Auth.resendSignUp(userInfo.email) on button Resend code.\nIn case of a successful method call"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"Auth.confirmSignUp(email, code, { forceAliasCreation: true })\n")),Object(o.b)("p",null,"we must call the method"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"Auth.signIn(email, password)\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step11",src:t(138).default})),Object(o.b)("h2",{id:"user-screen"},"User screen"),Object(o.b)("p",null,"Once it successfully done, go to the USER screen, which we create with the exit button for the application and clearing the src/screens/Authenticator/User/index.tsx tokens"),Object(o.b)("p",null,Object(o.b)("img",{alt:"User screen",src:t(249).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useState, useEffect, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport * as Keychain from 'react-native-keychain'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { AppContainer, Button } from '../../../components'\nimport { goHome } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'HELLO'>\n\ntype UserT = {\n navigation: ProfileScreenNavigationProp\n}\n\nconst User = ({ navigation }: UserT): ReactElement => {\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n useEffect(() => {\n const checkUser = async (): Promise<void> => {\n await Auth.currentAuthenticatedUser()\n }\n checkUser()\n }, [navigation])\n\n const _onPress = async (): Promise<void> => {\n setLoading(true)\n try {\n await Auth.signOut()\n await Keychain.resetInternetCredentials('auth')\n goHome(navigation)()\n } catch (err) {\n setError(err.message)\n }\n }\n\n return (\n <AppContainer message={error} loading={loading}>\n <Button title=\"Sign Out\" onPress={_onPress} />\n </AppContainer>\n )\n}\n\nexport { User }\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step12",src:t(159).default})),Object(o.b)("h2",{id:"signin-screen"},"SignIn screen"),Object(o.b)("p",null,"After the user is registered, we must provide the user with the opportunity to enter the application through login and password. To do this, we create the SIGN_IN src/screens/Authenticator/SignIn/index.tsx screen"),Object(o.b)("p",null,Object(o.b)("img",{alt:"SignIn screen",src:t(250).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport * as Keychain from 'react-native-keychain'\nimport { Formik } from 'formik'\nimport * as Yup from 'yup'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { AppContainer, Button, Space, ButtonLink, TextError, Input } from '../../../components'\nimport { onScreen, goBack } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'SIGN_IN'>\n\ntype SignUpT = {\n navigation: ProfileScreenNavigationProp\n}\n\nconst SignIn = ({ navigation }: SignUpT): ReactElement => {\n const [userInfo, setUserInfo] = useState({ email: '', password: '' })\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n const _onPress = async (values: { email: string; password: string }): Promise<void> => {\n setLoading(true)\n setError('')\n try {\n const { email, password } = values\n const user = await Auth.signIn(email, password)\n await Keychain.setInternetCredentials('auth', email, password)\n user && onScreen('USER', navigation)()\n setLoading(false)\n } catch ({ code }) {\n setLoading(false)\n if (code === 'UserNotConfirmedException') {\n setError('Account not verified yet')\n } else if (code === 'PasswordResetRequiredException') {\n setError('Existing user found. Please reset your password')\n } else if (code === 'NotAuthorizedException') {\n setUserInfo(values)\n setError('Forgot Password?')\n } else if (code === 'UserNotFoundException') {\n setError('User does not exist!')\n } else {\n setError(code)\n }\n }\n }\n\n return (\n <>\n <AppContainer onPress={goBack(navigation)} title=\"Sign In\" loading={loading} message={error}>\n <Formik\n enableReinitialize\n initialValues={userInfo}\n onSubmit={(values): Promise<void> => _onPress(values)}\n validationSchema={Yup.object().shape({\n email: Yup.string()\n .email()\n .required(),\n password: Yup.string()\n .min(6)\n .required()\n })}\n >\n {({ values, handleChange, errors, setFieldTouched, touched, handleSubmit }): ReactElement => (\n <>\n <Space height={90} />\n <Input\n name=\"email\"\n value={values.email}\n onChangeText={handleChange('email')}\n onBlur={(): void => setFieldTouched('email')}\n placeholder=\"E-mail\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n />\n <Input\n name=\"password\"\n value={values.password}\n onChangeText={handleChange('password')}\n onBlur={(): void => setFieldTouched('password')}\n placeholder=\"Password\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n secureTextEntry\n />\n {error !== 'Forgot Password?' && <TextError title={error} textStyle={{ alignSelf: 'center' }} />}\n {error === 'Forgot Password?' && (\n <ButtonLink\n title={error}\n onPress={onScreen('FORGOT', navigation, userInfo)}\n textStyle={{ alignSelf: 'center' }}\n />\n )}\n <Button title=\"Sign In\" onPress={handleSubmit} />\n <Space height={130} />\n </>\n )}\n </Formik>\n </AppContainer>\n </>\n )\n}\n\nexport { SignIn }\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step13",src:t(251).default})),Object(o.b)("h2",{id:"forgot-password-screen"},"Forgot password screen"),Object(o.b)("p",null,"If successful, we send the user to the USER screen, which we have already done, and if the user has forgotten or entered the password incorrectly, then we show the Forgot Password error and suggest resetting the password."),Object(o.b)("p",null,Object(o.b)("img",{alt:"Forgot password",src:t(252).default})),Object(o.b)("p",null,"To do this, we create the FORGOT src/screens/Authenticator/Forgot/index.tsx screen"),Object(o.b)("p",null,Object(o.b)("img",{alt:"Forgot password",src:t(253).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport { Formik } from 'formik'\nimport * as Yup from 'yup'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { RouteProp } from '@react-navigation/native'\nimport { AppContainer, Button, Input, Space } from '../../../components'\nimport { onScreen, goBack } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'FORGOT'>\ntype ProfileScreenRouteProp = RouteProp<RootStackParamList, 'FORGOT'>\n\ntype ForgotT = {\n navigation: ProfileScreenNavigationProp\n route: ProfileScreenRouteProp\n}\n\nconst Forgot = ({ route, navigation }: ForgotT): ReactElement => {\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n const _onPress = async (values: { email: string }): Promise<void> => {\n setLoading(true)\n try {\n const { email } = values\n const user = await Auth.forgotPassword(email)\n user && onScreen('FORGOT_PASSWORD_SUBMIT', navigation, values)()\n setLoading(false)\n } catch (err) {\n setError(error)\n }\n }\n\n return (\n <>\n <AppContainer title=\"Forgot\" onPress={goBack(navigation)} loading={loading} message={error}>\n <Formik\n initialValues={{ email: route.params.email || '' }}\n onSubmit={(values): Promise<void> => _onPress(values)}\n validationSchema={Yup.object().shape({\n email: Yup.string()\n .email()\n .required()\n })}\n >\n {({ values, handleChange, errors, setFieldTouched, touched, handleSubmit }): ReactElement => (\n <>\n <Input\n name=\"email\"\n value={values.email}\n onChangeText={handleChange('email')}\n onBlur={(): void => setFieldTouched('email')}\n placeholder=\"E-mail\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n />\n <Space height={30} />\n <Button title=\"Confirm\" onPress={handleSubmit} />\n <Space height={100} />\n </>\n )}\n </Formik>\n </AppContainer>\n </>\n )\n}\n\nexport { Forgot }\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step14",src:t(254).default})),Object(o.b)("h2",{id:"forgot-password-submit"},"Forgot password submit"),Object(o.b)("p",null,"After confirming the e-mail, we call the Auth.forgotPassword (email) method and if there is such a user, we send the user to the FORGOT_PASSWORD_SUBMIT src/screens/Authenticator/ForgotPassSubmit/index.tsx screen"),Object(o.b)("p",null,Object(o.b)("img",{alt:"ForgotPassSubmit",src:t(255).default})),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-tsx"}),"import React, { useState, ReactElement } from 'react'\nimport { Auth } from 'aws-amplify'\nimport * as Keychain from 'react-native-keychain'\nimport { Formik } from 'formik'\nimport * as Yup from 'yup'\nimport { StackNavigationProp } from '@react-navigation/stack'\nimport { RouteProp } from '@react-navigation/native'\nimport { AppContainer, Button, Space, Input, TextError } from '../../../components'\nimport { onScreen, goBack } from '../../../constants'\nimport { RootStackParamList } from '../../../AppNavigator'\n\ntype ProfileScreenNavigationProp = StackNavigationProp<RootStackParamList, 'FORGOT_PASSWORD_SUBMIT'>\ntype ProfileScreenRouteProp = RouteProp<RootStackParamList, 'FORGOT_PASSWORD_SUBMIT'>\n\ntype ForgotPassSubmitT = {\n navigation: ProfileScreenNavigationProp\n route: ProfileScreenRouteProp\n}\n\nconst ForgotPassSubmit = ({ route, navigation }: ForgotPassSubmitT): ReactElement => {\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState('')\n\n const _onPress = async (values: { email: string; password: string; code: string }): Promise<void> => {\n setLoading(true)\n try {\n const { email, code, password } = values\n await Auth.forgotPasswordSubmit(email, code, password)\n await Keychain.setInternetCredentials('auth', email, password)\n await Auth.signIn(email, password)\n onScreen('USER', navigation)()\n setLoading(false)\n } catch (err) {\n setLoading(false)\n setError(err.message)\n }\n }\n\n return (\n <>\n <AppContainer title=\"Confirmation\" onPress={goBack(navigation)} loading={loading} message={error}>\n <Formik\n initialValues={{ email: route.params.email || '', code: '', password: '', passwordConfirmation: '' }}\n onSubmit={(values): Promise<void> => _onPress(values)}\n validationSchema={Yup.object().shape({\n email: Yup.string()\n .email()\n .required(),\n code: Yup.string()\n .min(6)\n .required(),\n password: Yup.string()\n .min(6)\n .required(),\n passwordConfirmation: Yup.string()\n .min(6)\n .required()\n })}\n >\n {({ values, handleChange, errors, setFieldTouched, touched, handleSubmit }): ReactElement => (\n <>\n <Input\n name=\"email\"\n value={values.email}\n onChangeText={handleChange('email')}\n onBlur={(): void => setFieldTouched('email')}\n placeholder=\"E-mail\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n />\n <Input\n name=\"code\"\n value={values.code}\n onChangeText={handleChange('code')}\n onBlur={(): void => setFieldTouched('code')}\n placeholder=\"Code\"\n touched={touched}\n errors={errors}\n />\n <Input\n name=\"password\"\n value={values.password}\n onChangeText={handleChange('password')}\n onBlur={(): void => setFieldTouched('password')}\n placeholder=\"Password\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n secureTextEntry\n />\n <Input\n name=\"passwordConfirmation\"\n value={values.passwordConfirmation}\n onChangeText={handleChange('passwordConfirmation')}\n onBlur={(): void => setFieldTouched('passwordConfirmation')}\n placeholder=\"Password confirm\"\n touched={touched}\n errors={errors}\n autoCapitalize=\"none\"\n secureTextEntry\n />\n {error !== '' && <TextError title={error} textStyle={{ alignSelf: 'center' }} />}\n <Space height={30} />\n <Button title=\"Confirm\" onPress={handleSubmit} />\n <Space height={80} />\n </>\n )}\n </Formik>\n </AppContainer>\n </>\n )\n}\n\nexport { ForgotPassSubmit }\n")),Object(o.b)("p",null,"where, after entering the code sent to the mail, the new password and confirming it, we call the password change method"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"Auth.forgotPasswordSubmit(email, code, password)\n")),Object(o.b)("p",null,"whose success sends the user to the USER screen."),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step15",src:t(256).default})),Object(o.b)("h2",{id:"linking-screens"},"Linking screens"),Object(o.b)("p",null,"We connect all created components in src/screens/Authenticator/index.ts"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-ts"}),"export * from './Hello'\nexport * from './User'\nexport * from './SignIn'\nexport * from './SignUp'\nexport * from './Forgot'\nexport * from './ForgotPassSubmit'\nexport * from './ConfirmSignUp'\n")),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step16",src:t(257).default})),Object(o.b)("h2",{id:"udpate-appnavigator"},"Udpate AppNavigator"),Object(o.b)("p",null,"Updating the navigation configuration file src/AppNavigator.tsx :"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),'import * as React from \'react\'\nimport { createStackNavigator } from \'@react-navigation/stack\'\nimport { Hello, SignUp, SignIn, ConfirmSignUp, User, Forgot, ForgotPassSubmit } from \'./screens/Authenticator\'\n\nconst Stack = createStackNavigator()\n\nexport type RootStackParamList = {\n HELLO: undefined\n SIGN_UP: undefined\n SIGN_IN: undefined\n FORGOT: { email: string }\n FORGOT_PASSWORD_SUBMIT: { email: string }\n CONFIRM_SIGN_UP: { email: string; password: string }\n USER: undefined\n}\n\nconst AppNavigator = (): React.ReactElement => {\n return (\n <Stack.Navigator\n screenOptions={{\n headerShown: false\n }}\n initialRouteName="HELLO"\n >\n <Stack.Screen name="HELLO" component={Hello} />\n <Stack.Screen name="SIGN_UP" component={SignUp} />\n <Stack.Screen name="SIGN_IN" component={SignIn} />\n <Stack.Screen name="FORGOT" component={Forgot} />\n <Stack.Screen name="FORGOT_PASSWORD_SUBMIT" component={ForgotPassSubmit} />\n <Stack.Screen name="CONFIRM_SIGN_UP" component={ConfirmSignUp} />\n <Stack.Screen name="USER" component={User} />\n </Stack.Navigator>\n )\n}\n\nexport default AppNavigator\n')),Object(o.b)("p",null,Object(o.b)("img",{alt:"Step17",src:t(258).default})),Object(o.b)("h2",{id:"debug"},"Debug"),Object(o.b)("p",null,"In order to understand what happens with tokens in your application, add in the root/index.js"),Object(o.b)("pre",null,Object(o.b)("code",Object(a.a)({parentName:"pre"},{className:"language-jsx"}),"window.LOG_LEVEL = 'DEBUG'\n")),Object(o.b)("p",null,"We launch the application and get custom authentication."),Object(o.b)("h2",{id:"done-"},"Done \u2705"),Object(o.b)("p",null,Object(o.b)("a",Object(a.a)({parentName:"p"},{href:"https://www.patreon.com/bePatron?u=34467235"}),Object(o.b)("img",{alt:"Become a Patron!",src:t(112).default}))))}u.isMDXComponent=!0}}]);