// This file renders the login screen. import { LoginFlow, UpdateLoginFlowBody } from "@ory/client-fetch" import { useFocusEffect } from "@react-navigation/native" import { StackScreenProps } from "@react-navigation/stack" import React, { useContext, useState } from "react" import { SessionContext } from "../../helpers/auth" import { logSDKError } from "../../helpers/errors" import { handleFormSubmitError } from "../../helpers/form" import { newOrySdk } from "../../helpers/sdk" import { AuthContext } from "../AuthProvider" import AuthLayout from "../Layout/AuthLayout" import ProjectPicker from "../Layout/ProjectPicker" import { RootStackParamList } from "../Navigation" import { SelfServiceFlow } from "../Ory/Ui" import { ProjectContext } from "../ProjectProvider" import AuthSubTitle from "../Styled/AuthSubTitle" import NavigationCard from "../Styled/NavigationCard" import StyledCard from "../Styled/StyledCard" import * as AuthSession from "expo-auth-session" type Props = StackScreenProps const Login = ({ navigation, route }: Props) => { const { project } = useContext(ProjectContext) const { setSession, sessionToken } = useContext(AuthContext) const [flow, setFlow] = useState(undefined) const initializeFlow = () => newOrySdk(project) .createNativeLoginFlow({ aal: route.params.aal, refresh: route.params.refresh, xSessionToken: sessionToken, // If you do use social sign in, please add the following URLs to your allowed return to URLs. // If you the app is running on an emulator or physical device: exp://localhost:8081 // If you are using the web version: http://localhost:19006 (or whatever port you are using) // If that does not work, please see the documentation of makeRedirectURI for more information: https://docs.expo.dev/versions/latest/sdk/auth-session/#authsessionmakeredirecturioptions // If you don't use Social sign in, you can comment out the following line. returnTo: AuthSession.makeRedirectUri({ preferLocalhost: true, path: "/Callback", }), returnSessionTokenExchangeCode: true, }) .then((f) => setFlow(f)) .catch(logSDKError) const refetchFlow = () => newOrySdk(project) .getLoginFlow({ id: flow!.id }) .then((f) => setFlow({ ...flow, ...f, // The GET response may not include the exchange code, and the // client-fetch deserializer explicitly sets missing fields to // undefined which would override the original value via spread. session_token_exchange_code: f.session_token_exchange_code ?? flow?.session_token_exchange_code, }), ) .catch(logSDKError) // When the component is mounted, we initialize a new use login flow: useFocusEffect( React.useCallback(() => { initializeFlow() return () => { setFlow(undefined) } }, [project]), ) const setSessionAndRedirect = (session: SessionContext) => { setSession(session) setTimeout(() => { navigation.navigate("Home") }, 100) } // This will update the login flow with the user provided input: const onSubmit = (payload: UpdateLoginFlowBody) => flow ? newOrySdk(project) .updateLoginFlow({ flow: flow.id, updateLoginFlowBody: payload, xSessionToken: sessionToken, }) .then((data) => { // For refresh/aal2 logins, Kratos may not return a new session_token // (the token is unchanged). In that case, preserve the existing token. const result: SessionContext = { session: data.session, session_token: data.session_token || sessionToken || "", } return result }) // Looks like everything worked and we have a session! .then(setSessionAndRedirect) .catch( handleFormSubmitError( flow, setFlow, initializeFlow, setSessionAndRedirect, refetchFlow, ), ) : Promise.resolve() return ( Sign in to your account navigation.navigate("Registration")} /> navigation.navigate("Recovery")} /> ) } export default Login