Sign with Redirect

Once the authentication is complete, we will get the user's JoyID information, such as username, address, credential, etc. In this guide, we will continue our previous journey in Auth with Redirect by signing a challenge after the authentication is complete.

To redirect to JoyID App to sign a challenge, we need to do the following steps:

Step 1: Save authentication info

In the previous guide, we have already authenticated the user with JoyID, and we have got the user's JoyID information. Now we need to save the user's JoyID information. We can save it in the local storage, or in the state of the React component, or in the Vuex store of the Vue app, etc.

React
import * as React from 'react';
import { authWithRedirect, authCallback } from '@joyid/core';
import './style.css';

export default function App() {
  const [authInfo, setAuthInfo] = React.useState(null);
  const isRedirectFromJoyID = new URL(location.href).searchParams.has(
      'joyid-redirect'
  );
  const authOnClick = async () =>  {
      authWithRedirect({
          redirectURL: location.href,
          name: 'Awesome App',
          challenge: 'Sign this for me',
          logo: 'https://reactjs.org/logo-180x180.png',
      });
  };
  React.useEffect(() => {
      if (isRedirectFromJoyID) {
          const authRes = authCallback();
          if (authRes.error == null && authRes.type === 'Auth') {
              setAuthInfo(authRes)
          }
      }
  }, []);
  return (
      <div>
          <h1>Hello JoyID!</h1>
          <button onClick={authOnClick}>Auth With JoyID</button>
      </div>
  );
}
Vue
<template>
  <div id="app">
      <h1>Hello JoyID!</h1>
      <button @click="auth">Auth with JoyID</button>
  </div>
</template>

<script>
import { authWithRedirect, authCallback } from '@joyid/core';
export default {
  name: 'App',
  data() {
      return {
          authInfo: null
      }
  },
  methods: {
      async auth() {
          authWithRedirect({
              redirectURL: location.href,
              name: 'Awesome App',
              challenge: 'Sign this for me',
              logo: 'https://vuejs.org/images/logo.png',
          });
      },
  },
  created() {
      const isRedirectFromJoyID = new URL(location.href).searchParams.has(
          'joyid-redirect'
      );

      if (isRedirectFromJoyID) {
          const res = authCallback();
          if (res.error == null) {
              this.authInfo = res.data;
          }
      }
  },
};
</script>

Step 2: Sign the challenge

After the authentication is complete, we need to add a button element and listen to the click event. When the user clicks the button, we will call the signWithRedirect function to sign the challenge with the user's JoyID.

Note that address is required in the signWithRedirect function. You can only sign the challenge with the user's JoyID if you know the user's address. The address is included in authentication info.

Verify the credential before signing the challenge

React
import * as React from 'react';
import {
  authCallback,
  authWithRedirect,
  signCallback,
  signWithRedirect,
} from '@joyid/core';
import './style.css';

export default function App() {
  ...
  const signOnClick = async () => {
      signWithRedirect({
          redirectURL: location.origin + '/',
          name: 'Awesome App',
          challenge,
          logo: 'https://reactjs.org/logo-180x180.png',
          address: authInfo?.address,
          state,
      });
  };
  ...
  return (
      ...
      <button onClick={signOnClick}>Sign With JoyID</button>
      ...
  );
}
Vue
<template>
  <div id="app">
      ...
      <button @click="sign">Sign With JoyID</button>
      ...
  </div>
</template>

<script>
import {
  authCallback,
  authWithRedirect,
  signCallback,
  signWithRedirect,
} from '@joyid/core';
import { ref } from 'vue';

export default {
  name: 'App',
  methods: {
      ...
      sign() {
          signWithRedirect({
              redirectURL: location.origin + '/',
              name: 'Awesome App',
              challenge: this.state.challenge,
              logo: 'https://vuejs.org/images/logo.png',
              address: this.state.authInfo?.address,
              state: this.state,
          });
      },
      ...
  },
};
</script>

Step 3: Get redirected data

After the user signed with JoyID App, the user will be redirected back to your App with the result in the URL query string. We need to call signCallback function in your redirected page to get the result.

In this step, we save all UI states and pass to the JoyID App via the state parameter of signWithRedirect function. When the signing is done, the same UI states are returned via the signCallback function, which keeps our UI continuous. But this is not the only way to maintain UI continuity after redirection, you can also save UI state to localStorage or server side, or even just ignore UI continuity.

React
import * as React from 'react';
import {
  authCallback,
  authWithRedirect,
  signCallback,
  signWithRedirect,
} from '@joyid/core';
import './style.css';

const initState = {
  authInfo: null,
  challenge: 'Sign this for me',
};

type Action = {
  type: 'challenge' | 'authInfo';
  payload: any;
};

const reducer = (state: typeof initState, action: Action): typeof initState => {
  const { type, payload } = action;
  switch (type) {
      case 'challenge': {
          return {
              ...state,
              challenge: payload,
          };
      }
      case 'authInfo': {
          return {
              ...state,
              authInfo: payload,
          };
      }
      default: {
          return state;
      }
  }
};

export default function App() {
  const isRedirectFromJoyID = new URL(location.href).searchParams.has(
      'joyid-redirect'
  );

  const [state, dispatch] = React.useReducer(reducer, initState);
  const { challenge, authInfo } = state;

  const authOnClick = async () => {
      authWithRedirect({
          redirectURL: location.origin + '/',
          name: 'Awesome App',
          challenge: 'Sign this for me',
          logo: 'https://reactjs.org/logo-180x180.png',
          state,
      });
  };
  const signOnClick = async () => {
      signWithRedirect({
          redirectURL: location.origin + '/',
          name: 'Awesome App',
          challenge,
          logo: 'https://reactjs.org/logo-180x180.png',
          address: authInfo?.address,
          state,
      });
  };
  React.useEffect(() => {
      if (isRedirectFromJoyID) {
          const authRes = authCallback();
          if (authRes.error == null && authRes.type === 'Auth') {
              dispatch({ type: 'authInfo', payload: authRes.data });
          }
          const signRes = signCallback();
          if (signRes.error == null && signRes.type === 'SignMessage') {
              const { state, ...data } = signRes.data;
              const { authInfo, challenge } = state as typeof initState;
              dispatch({ type: 'challenge', payload: challenge });
              dispatch({ type: 'authInfo', payload: authInfo });
              // see console for details
              console.log(data);
          }
      }
  }, []);
  return (
      <div>
          <h1>Hello JoyID!</h1>
          {authInfo ? null : (
              <button onClick={authOnClick}>Auth With JoyID</button>
          )}
          {authInfo ? (
              <div>
                  <textarea
                      value={challenge}
                      onChange={(e) =>
                          dispatch({
                              type: 'challenge',
                              payload: e.target.value,
                          })
                      }
                  />
                  <button onClick={signOnClick}>Sign With JoyID</button>
              </div>
          ) : null}
      </div>
  );
}
Vue
<template>
  <div id="app">
      <h1>Hello JoyID!</h1>
      <button @click="auth" v-if="!state.authInfo">Auth with JoyID</button>
      <div v-else>
          <textarea v-model="state.challenge" />
          <button @click="sign">Sign With JoyID</button>
      </div>
  </div>
</template>

<script>
import {
  authCallback,
  authWithRedirect,
  signCallback,
  signWithRedirect,
} from '@joyid/core';
import { ref } from 'vue';

export default {
  name: 'App',
  methods: {
      auth() {
          authWithRedirect({
              redirectURL: location.origin + '/',
              name: 'Awesome App',
              challenge: 'Sign this for me',
              logo: 'https://vuejs.org/images/logo.png',
              state: this.state,
          });
      },
      sign() {
          signWithRedirect({
              redirectURL: location.origin + '/',
              name: 'Awesome App',
              challenge: this.state.challenge,
              logo: 'https://vuejs.org/images/logo.png',
              address: this.state.authInfo?.address,
              state: this.state,
          });
      },
  },
  created() {
      const isRedirectFromJoyID = new URL(location.href).searchParams.has(
          'joyid-redirect'
      );

      if (isRedirectFromJoyID) {
          const authRes = authCallback();
          if (authRes.error == null && authRes.type === 'Auth') {
              this.state.authInfo = authRes.data;
          }
          const signRes = signCallback();
          if (signRes.error == null && signRes.type === 'SignMessage') {
              const { state, ...data } = signRes.data;
              const { authInfo, challenge } = state;
              this.state.challenge = challenge;
              this.state.authInfo = authInfo;
              // see console for details
              console.log(data);
          }
      }
  },
  setup() {
      const state = ref({
          authInfo: null,
          challenge: 'Sign this for me',
      });
      return { state };
  },
};
</script>
To learn more about the signCallback function, please check the API Reference.

Try it out

For browser security reasons, you may need to open the URL of this Demo ( React, Vue ) in order to test it properly.
Loading Sandbox...
Loading Sandbox...