Directory Structure: └── ./ └── pages ├── guides │ ├── dashboard │ │ ├── custom-auth │ │ │ ├── auth-token.mdx │ │ │ ├── oidc-token.mdx │ │ │ └── telegram-mini-app.mdx │ │ ├── external-auth │ │ │ ├── accelbyte.mdx │ │ │ ├── firebase.mdx │ │ │ ├── lootlocker.mdx │ │ │ ├── playfab.mdx │ │ │ └── supabase.mdx │ │ ├── password │ │ │ ├── custom-smtp.mdx │ │ │ └── security.mdx │ │ ├── social-login │ │ │ ├── auth-discord.mdx │ │ │ ├── auth-epic.mdx │ │ │ ├── auth-facebook.mdx │ │ │ ├── auth-google.mdx │ │ │ ├── auth-line.mdx │ │ │ ├── auth-telegram.mdx │ │ │ └── auth-twitter.mdx │ │ ├── dev.mdx │ │ ├── ecosystem.mdx │ │ ├── external-auth.mdx │ │ ├── faqs.mdx │ │ ├── gas-erc20.mdx │ │ ├── gas-sponsorship.mdx │ │ ├── keys.mdx │ │ ├── notifications.mdx │ │ ├── project-billing.mdx │ │ ├── social-login.mdx │ │ ├── sponsor-rules.mdx │ │ ├── team.mdx │ │ ├── users.mdx │ │ └── webhooks.mdx │ ├── ecosystem │ │ ├── configuration │ │ │ ├── branding.mdx │ │ │ ├── ecosystem-id.mdx │ │ │ ├── login-methods.mdx │ │ │ ├── samples.mdx │ │ │ └── wallet-ui.mdx │ │ ├── batch-transactions.mdx │ │ ├── create-wallet-button.mdx │ │ ├── faqs.mdx │ │ ├── gas-policies.mdx │ │ ├── getting-started.mdx │ │ ├── intro.mdx │ │ ├── libraries.mdx │ │ ├── react-native-integration.mdx │ │ ├── signatures.mdx │ │ └── web-app-wagmi.mdx │ ├── javascript │ │ ├── auth │ │ │ ├── user-management │ │ │ │ └── linking.mdx │ │ │ ├── external-auth.mdx │ │ │ ├── external-wallet.mdx │ │ │ ├── guest.mdx │ │ │ ├── oauth-login.mdx │ │ │ ├── password.mdx │ │ │ ├── user-management.mdx │ │ │ └── user-sessions.mdx │ │ ├── embedded-signer │ │ │ ├── advanced │ │ │ │ ├── iframe.mdx │ │ │ │ └── shield.mdx │ │ │ ├── advanced.mdx │ │ │ ├── export-key.mdx │ │ │ ├── recovery.mdx │ │ │ ├── sign-messages.mdx │ │ │ └── update-recovery.mdx │ │ ├── resources │ │ │ └── telegram-react.mdx │ │ ├── smart-wallet │ │ │ ├── advanced │ │ │ │ ├── session-keys.mdx │ │ │ │ ├── sign-custodial.mdx │ │ │ │ ├── social-recovery.mdx │ │ │ │ └── transfer-ownership.mdx │ │ │ ├── guides │ │ │ │ ├── bridge.mdx │ │ │ │ └── exchange.mdx │ │ │ ├── connected-wallets.mdx │ │ │ ├── funding.mdx │ │ │ ├── libraries.mdx │ │ │ └── send.mdx │ │ ├── auth.mdx │ │ ├── faqs.mdx │ │ ├── features.mdx │ │ ├── react-native.mdx │ │ ├── resources.mdx │ │ ├── troubleshooting.mdx │ │ ├── use-openfort.mdx │ │ └── wallets.mdx │ ├── server │ │ ├── quickstarts │ │ │ ├── api.mdx │ │ │ └── sdk.mdx │ │ ├── access-token.mdx │ │ ├── architecture.mdx │ │ ├── dev.mdx │ │ ├── pregenerate-wallets.mdx │ │ ├── setup.mdx │ │ ├── usage.mdx │ │ └── webhooks.mdx │ ├── unity │ │ ├── auth │ │ │ ├── email.mdx │ │ │ ├── external-wallet.mdx │ │ │ ├── guest.mdx │ │ │ ├── oauth.mdx │ │ │ ├── third-party.mdx │ │ │ └── user-sessions.mdx │ │ ├── embedded-signer │ │ │ ├── recovery.mdx │ │ │ ├── sign-messages.mdx │ │ │ └── state.mdx │ │ ├── resources │ │ │ ├── backend │ │ │ │ ├── firebase-extension.mdx │ │ │ │ ├── playfab.mdx │ │ │ │ └── unity-gaming-services.mdx │ │ │ ├── ads-unity.mdx │ │ │ ├── android-iap-unity.mdx │ │ │ ├── apple-iap-unity.mdx │ │ │ ├── captcha-unity.mdx │ │ │ ├── telegram-unity.mdx │ │ │ └── token-bound-accounts.mdx │ │ ├── smart-wallet │ │ │ ├── advanced │ │ │ │ └── session-keys.mdx │ │ │ ├── connected-wallets.mdx │ │ │ └── send.mdx │ │ ├── quickstart.mdx │ │ ├── resources.mdx │ │ ├── troubleshooting.mdx │ │ └── webgl.mdx │ ├── dashboard.mdx │ ├── ecosystem.mdx │ ├── getting-started.mdx │ ├── react-native.mdx │ ├── server.mdx │ ├── unity.mdx │ └── unreal-engine.mdx ├── reference │ └── api │ └── [...slug].tsx ├── addresses.mdx ├── api-keys.mdx ├── chains.mdx ├── libraries.mdx └── security.mdx --- File: /pages/guides/dashboard/custom-auth/auth-token.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Custom Generic Auth Token', description: 'Configure a custom auth token', subtitle: 'Learn how to setup your custom auth token', breadcrumb: 'Authentication', } Generic authentication serves as an alternative for those utilizing their own authentication server. This method accommodates various authentication types not currently supported, such as `Discord`, `Twitter`, `GitHub`, or bespoke systems. Essential steps and requirements for generic authentication through an endpoint include: - Post-login, generate a public identifier to recognize the user. - Relay this identifier to the embedded signer to initiate wallet creation. - An endpoint you provide will be contacted to confirm the user's identity, upon which we'll create a wallet if the information is valid. You'll need to supply an endpoint for identity verification. Additional headers for request authentication can be passed and will accompany every verification request to your endpoint. ## Authenticating Users with Generic Authentication ### Configure your server Within the server that handles auhentication requests, you'll need to implement an endpoint responsible for verifying the user's identity. This endpoint should accept a `POST` request with a JSON body containing the `payload` field, which corresponds to the user's public identifier. ```json { "payload": "public_identifier" // you can put any data you want here (as long as it's a string) } ``` After returning a JSON response, the SDK will create a wallet for the user if the response is valid. The response should contain the following fields: ```json { "userId": "unique_user_id", // A unique identifier for the user, used for wallet identification if no email is provided "email": "user_email" // optional } ``` ### Set up your provider To set up your Custom Authentication with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
custom auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/custom-auth/oidc-token.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Custom OIDC compatible Auth', description: 'Configure a custom OIDC compatible auth', subtitle: 'Learn how to setup your custom OIDC compatible auth', breadcrumb: 'Authentication', } OIDC authentication setup is a viable choice when leveraging an external authentication provider such as `Auth0`, `Cognito`, etc., that offers JWK publication for token authenticity verification. An OIDC authentication framework employs a public-private key pair, utilizing the private key to sign authentication tokens. The public key is made accessible via a public URL in JWKS format, typically found at `https://{domain}.com/.well-known/jwks.json`. When a user logs in, an idToken, a JWT, is produced and signed with the private key, following OIDC specifications for token field requirements. This JWT is then used within the embedded signer to create a user wallet. The verification of the JWT against the public key confirms its authenticity, allowing wallet generation based on the subject (user identifier) within the idToken. Input Requirements: - JWKS File URL (public key): Validates the token's authentic signature. - idToken's `aud` value: Confirms that the intended recipient of the token is correct. ## Authenticating Users with OIDC-Compatible Authentication ### Set up your provider To set up your OIDC Authentication with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
oidc auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/custom-auth/telegram-mini-app.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate wallet in your Telegram mini-app', title: 'Seamless login with Telegram mini-app', description: 'Learn how you can integrate EVM wallet in your Telegam mini-app', subtitle: 'Integrate wallet in your Telegram mini-app', breadcrumb: 'Authentication', } You can integrate Openfort to enable login directly from within a Telegram bot or Telegram mini-app. ## Configuration Follow [this guide](https://core.telegram.org/bots/tutorial#obtain-your-bot-token) to create a telegram bot. After creating a Telegram bot, you must set your domain using the `/setdomain` command in the `@BotFather` chat. You will need to provide the following to Openfort via the Openfort Dashboard upon completion: - Bot token
Telegram mini-app
The `telegramMiniApp`, uses the signed `initDataRaw` from the `telegramSDK` available in the mini app as third party authentication. It does not have any kind of refresh token since Telegram is in charge of issuing new authentications. This method can be used directly from the mini app without requiring interaction with the user as he is already authenticated with the mini app. Since you need to set your bot's allowed domain you'll need to use a tunneling tool for local development such as [ngrok](https://ngrok.com/). ## Samples
{'Learn how integrate with our mini-app sample'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth/accelbyte.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'AccelByte Auth', description: 'Integrate with AccelByte.', subtitle: 'Learn how to interact with AccelByte', breadcrumb: 'Authentication', } AccelByte offers robust backend services for building and operating online games, featuring scalable cloud infrastructure, matchmaking, and cross-platform player accounts. Their solutions focus on enhancing multiplayer experiences while providing developers with the flexibility to customize game services. ## Set up your provider To set up Accelbyte to authenticate players with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
accelbyte auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth/firebase.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Firebase Auth', description: 'Integrate with Firebase.', subtitle: 'Learn how to interact with Firebase', breadcrumb: 'Authentication', } Firebase is a development platform from Google that provides a variety of tools and services to help developers build, improve, and grow their apps, with features such as databases, analytics, messaging, and crash reporting. It emphasizes easy integration and real-time updates, enabling developers to create rich, collaborative experiences. ## Prerequisites Head to your Project Settings in the Firebase Console and grab your Firebase Project ID. ## Set up your provider To set up Firebase to authenticate players with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
firebase auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth/lootlocker.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'LootLocker Auth', description: 'Integrate with LootLocker.', subtitle: 'Learn how to interact with LootLocker', breadcrumb: 'Authentication', } LootLocker offers robust backend services for building and operating online games, featuring scalable cloud infrastructure, matchmaking, and cross-platform player accounts. Their solutions focus on enhancing multiplayer experiences while providing developers with the flexibility to customize game services. ## Set up your provider To set up LootLocker to authenticate players with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
lootlocker auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth/playfab.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'PlayFab Auth', description: 'Integrate with PlayFab', subtitle: 'Learn how to interact with PlayFab Auth', breadcrumb: 'Authentication', } PlayFab provides a comprehensive suite of live game management services, including server hosting, data analytics, and liveOps utilities to streamline game development and monetization. It is designed to empower developers with the tools needed to engage players and drive revenue, all while minimizing overhead and time to market. ## Prerequisites To set up your PlayFab authentication with Openfort, you'll need to get the `Project ID`. 1. Visit the [PlayFab developer dashboard](https://developer.playfab.com/), select your title, and navigate to **_Settings wheel --> Title settings_**:
playfab title settings
2. In the **_API Features_** section, copy your **_Title ID_**:
get playfab title id
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth/supabase.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Supabase Auth', description: 'Integrate with Supabase.', subtitle: 'Learn how to interact with Supabase', breadcrumb: 'Authentication', } Supabase is an open-source alternative to Firebase. It provides a variety of tools and services to help with Postgres database, Authentication, instant APIs, Realtime, Functions, Storage and Vector embeddings. ## Prerequisites Head to your Project Settings in the Supabase Console and grab your Project URL and anon API Key. ## Set up your provider To set up Supabase to authenticate players with Openfort, visit your [dashboard provider settings](https://dashboard.openfort.xyz/players/auth/providers).
supabase auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/password/custom-smtp.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Password Security', description: 'How to work with passwords in Openfort Auth', breadcrumb: 'Authentication', } ## Custom SMTP At present, you can trial the Openfort platform by sending up to **3** emails per hour via the built-in service. The default email service as a whole is offered on a best effort basis: we will do our best to maintain it and will review usage of the service on a regular basis to see if the email service should be continued. As you progress toward production, you may find yourself wanting for a custom SMTP service in order to increase your limits. A custom SMTP server will allow you to set your own cap on the number of emails sent per hour. Beyond rate limits, an SMTP server might also help with: - Deliverability and Reputation Management - Scalability - Analytics and Tracking - Compliance and Anti Spam measures ## How to set up SMTP Head over to [Settings Page](https://dashboard.openfort.xyz/settings/configuration/auth) and hit "Enable Custom SMTP" under the SMTP Provider section. Fill in fields below with the relevant details obtained from your custom SMTP provider:
authenticated players
### SMTP providers You can use Openfort Auth with any major SMTP provider of your choosing. Some SMTP providers you could consider using are: - [Twilio SendGrid](https://docs.sendgrid.com/for-developers/sending-email/integrating-with-the-smtp-api) - [AWS SES](https://docs.aws.amazon.com/ses/latest/dg/send-email-smtp.html) ## Email templates You can customize the email messages used for the authentication flows. You can edit the following email templates: - Confirm signup - Reset Password
email templates
## Terminology The templating system provides the following variables for use: | Name | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `{{ .state }}` | Contains a 6-digit One-Time-Password (OTP). | | `{{ .email }}` | The user's email address. | | `{{ .redirectUrl }}` | Contains the redirect URL to confirm the email address to a new account. | ## Editing email templates Edit your email templates on the [Email Templates](https://dashboard.openfort.xyz/settings/configuration/templates) page. Below is an example for a verification of a sign up: ``` Subject: Confirm Reauthentication Body:

Confirm reauthentication

Enter the code: {{ .state }}

``` export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/password/security.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Password-based Auth', description: 'How to work with passwords in Openfort Auth', breadcrumb: 'Authentication', } You only need to enable this togle if you're developing an ecosystem wallets.
email setup
## Password security A password is more secure if it is harder to guess or brute-force. In theory, a password is harder to guess if it is longer. It is also harder to guess if it uses a larger set of characters (for example, digits, lowercase and uppercase letters, and symbols). This table shows the _minimum_ number of guesses that need to be tried to access a user's account: | Required characters | Length | Guesses | | -------------------------------------------- | ------ | ---------------- | | Digits only | 8 | ~ 227 | | Digits and letters | 8 | ~ 241 | | Digits, lower and uppercase letters | 8 | ~ 248 | | Digits, lower and uppercase letters, symbols | 8 | ~ 252 | In reality though, passwords are not always generated at random. They often contain variations of names, words, dates, and common phrases. Malicious actors can use these properties to guess a password in fewer attempts. There are hundreds of millions (and growing!) known passwords out there. Malicious actors can use these lists of leaked passwords to automate login attempts (known as credential stuffing) and steal or access sensitive user data. ### Password strength and leaked password protection To help protect your users, Openfort Auth sets strength constrains of the passwords used on your project. - Set a large minimum password length. Anything less than 8 characters is not recommended. - Set the required characters that must appear at least once in a user's password. Use the strongest option of requiring digits, lowercase and uppercase letters, and symbols. - Prevent the use of leaked passwords. Openfort Auth uses the open-source [HaveIBeenPwned.org Pwned Passwords API](https://haveibeenpwned.com/Passwords) to reject passwords that have been leaked and are known by malicious actors. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-discord.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Discord Login', description: 'Integrate with Discord Login', subtitle: 'Learn how to interact with Discord Login', breadcrumb: 'Authentication', } To enable Discord Auth for your project, you need to set up a Discord OAuth application and add the application credentials in the Openfort Dashboard. ## Overview Setting up Discord logins for your application consists of 3 parts: - Create and configure a Discord Project and App on the [Discord Developer Dashboard](https://discord.com/developers). - Add your Discord API Key and API Secret Key to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js). ### Configuration **Access your Discord account** - Go to [discord.com](https://discord.com/). - Click on `Login` at the top right to log in. - Once logged in, go to [discord.com/developers](https://discord.com/developers). - callback URL: `https://api.openfort.xyz/iam/v1/oauth/callback/discord` **Create a Discord application** - Click on `New Application` at the top right. - Enter the name of your application and click `Create`. - Click on `OAuth2` under `Settings` in the left side panel. - Click `Add Redirect` under `Redirects`. - Type or paste your `callback URL` into the `Redirects` box. - Click `Save Changes` at the bottom. - Copy your `Client ID` and `Client Secret` under `Client information`. **Add your Discord credentials into your Supabase project**
Discord Auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-epic.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Epic Games Login', description: 'Integrate with Epic Games Login', subtitle: 'Learn how to interact with Epic Games Login', breadcrumb: 'Authentication', } To enable Epic Games Auth for your project, you need to set up a Epic Games OAuth application and add the application credentials in the Openfort Dashboard. ## Overview Setting up Epic Games login for your application consists of 3 parts: - Create and configure a Epic Project and App on the [Epic Developer Dashboard](https://dev.epicgames.com/portal/en-US/). - Add your Epic API Key and API Secret Key to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js).
Epic Auth
### Configuration 1. Create an organization on Epic Games portal and create a new project. 2. Click on `Epic Account Services` and add a new applications: - Verify your application website and privacy policy URL - Save the API Key (client_id) and API Secret Key (client_secret) for later use. 3. Set up Epic Games in Openfort: - Go to the [Openfort dashboard](https://dashboard.openfort.xyz/players/auth/providers). - Click on Epic Enabled to turn it ON. - Enter the Epic Client ID and Epic Client Secret. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-facebook.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Facebook Login', description: 'Integrate with Facebook Login', subtitle: 'Learn how to interact with Facebook Login', breadcrumb: 'Authentication', } To enable Facebook Auth for your project, you need to set up a Facebook OAuth application and add the application credentials to your Openfort Dashboard. ## Overview Setting up Facebook logins for your application consists of 3 parts: - Create and configure a Facebook Application on the [Facebook Developers Site](https://developers.facebook.com/). - Add your Facebook keys to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js). ### Configuration - Go to [developers.facebook.com](https://developers.facebook.com). - Click on `Log In` at the top right to log in. **Create a Facebook app** - Click on `My Apps` at the top right. - Click `Create App` near the top right. - Select your app type and click `Continue`. - Fill in your app information, then click `Create App`. - This should bring you to the screen: `Add Products to Your App`. (Alternatively you can click on `Add Product` in the left sidebar to get to this screen.) **Set up Facebook login for your Facebook app** From the `Add Products to your App` screen: - Click `Setup` under `Facebook Login` - Skip the Quickstart screen, instead, in the left sidebar, click `Settings` under `Facebook Login` - Enter your callback URI (`https://api.openfort.xyz/iam/v1/oauth/callback/facebook`) under `Valid OAuth Redirect URIs` on the `Facebook Login Settings` page - Enter this in the `Valid OAuth Redirect URIs` box - Click `Save Changes` at the bottom right Be aware that you have to set the right use case permissions to enable Third party applications to read the email address. To do so: Under `Build Your App`, click on `Use Cases` screen. From there, do the following steps: - Click the Edit button in `Authentication and Account Creation` on the right side. This action will lead to the other page. - `public_profile` is set by default, so make sure it and `email` have status of **Ready for testing** in the redirected page. - If not, click the **Add** button in email on right side. **Copy your Facebook app ID and secret** - Click `Settings / Basic` in the left sidebar - Copy your App ID from the top of the `Basic Settings` page - Under `App Secret` click `Show` then copy your secret - Make sure all required fields are completed on this screen. **Enter your Facebook app ID and secret into your Supabase project**
Facbook Auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-google.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Google Login', description: 'Integrate with Google Login', subtitle: 'Learn how to interact with Google Login', breadcrumb: 'Authentication', } Openfort Auth supports Sign in with Google on the web, native Android applications and Chrome extensions. ## Overview Setting up Twitter logins for your application consists of 3 parts: - Create and configure a Google Project and App on the [Google Cloud Platform](https://console.cloud.google.com/home/dashboard). - Add your Google API Key and API Secret Key to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js). ### Configuration 1. Go to the [API Credentials page](https://console.cloud.google.com/apis/credentials). 2. Click `Create credentials` and choose `OAuth Client ID`. 3. For application type, choose `Web application`. 4. Under **Authorized redirect URLs**, enter the callback URL from the [Openfort dashboard](https://dashboard.openfort.xyz/players/auth/providers). Expand the Google Auth Provider section to display it. 5. When you finish configuring your credentials, you will be shown your client ID and secret. Add these to the Google Auth Provider section of the Openfort Dashboard.
Google Auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-line.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'LINE Login', description: 'Integrate with LINE Login', subtitle: 'Learn how to interact with LINE Login', breadcrumb: 'Authentication', } Integrate LINE Login into your web app (website) to make it easier for people to create an account and log in. ## Overview Setting up LINE login for your application consists of 3 parts: - Create and configure a LINE Project and App on the [LINE Dashboard](https://developers.line.biz/console/). - Add your LINE `Channel ID` and `Channel Secret` to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js).
LINE Auth
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-telegram.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Telegram Login', description: 'Integrate with Telegram Login', subtitle: 'Learn how to interact with Telegram Login', breadcrumb: 'Authentication', } Openfort enables developers to quickly integrate Login with Telegram into their applications. ## Overview There are two methods of authentication with Telegram. Telegram Auth requires the botUsername as an OAuth2 authentication flow with telegram, similarly to how you login with Google with an access/refresh token returned. This method goes through the screen you have seen with the [Continue with Telegram](https://core.telegram.org/widgets/login) button. Openfort also enables seamless Telegram login directly from within a Telegram bot or within Telegram Mini-Apps! [Refer to this guide](/docs/guides/dashboard/custom-auth/telegram-mini-app). ### Configuration Start the conversation with [BotFather](https://t.me/botfather) and follow [this guide](https://core.telegram.org/bots/tutorial#obtain-your-bot-token) to create a telegram bot. You will need to provide the following to Openfort via the Openfort Dashboard upon completion: - Bot token (Paste the token you recive from BotFather) - Bot name (Paste the bot's username) After creating a Telegram bot, you must set your domain using the `/setdomain` command in the `@BotFather` chat. Send this link 'https://oauth.openfort.xyz/telegram/callback'.
Epic Auth
Telegram login requires developers to create a Telegram bot with a bot secret. This bot secret controls the Telegram bot and is also used as a symmetric key for authentication. Control over this key enables a developer to sign over authentication data, meaning compromise of this key puts your users (and their accounts) at risk. **Securing this symmetric key is essential for the security of all of your app’s Telegram logins.** export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login/auth-twitter.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'X (Twitter) Login', description: 'Integrate with X Login', subtitle: 'Learn how to interact with X Login', breadcrumb: 'Authentication', } To enable Twitter Auth for your project, you need to set up a Twitter OAuth application and add the application credentials in the Openfort Dashboard. ## Overview Setting up Twitter logins for your application consists of 3 parts: - Create and configure a Twitter Project and App on the [Twitter Developer Dashboard](https://developer.twitter.com/en/portal/dashboard). - Add your Twitter API Key and API Secret Key to your [Openfort Project](https://dashboard.openfort.xyz/players/auth/providers). - Add the login code to your [Openfort JS Client App](https://github.com/openfort-xyz/openfort-js).
Twitter Auth
### Configuration 1. Create Project and App: - Click "+ Create Project", enter project name, and select use case. - Enter a project description and app name. - Copy and save your API Key (client_id) and API Secret Key (client_secret). 2. Set Up App Settings: - Click on "App settings". - Go to "User authentication settings" and click "Set up". 3. Configure App Permissions: - Turn ON "Request email from users". - Select "Web App" as the Type of App. - Enter Callback URL, Website URL, Terms of service URL, and Privacy policy URL. 4. Set up X in Openfort: - Go to the [Openfort dashboard](https://dashboard.openfort.xyz/players/auth/providers). - Click on Twitter Enabled to turn it ON. - Enter the Twitter Client ID and Twitter Client Secret. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/dev.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Backend wallets', breadcrumb: ({ route }) => { const pathParts = route.split('/').filter(Boolean); return pathParts.map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(' > '); }, } Backend wallets serve as an internal account for games and developers to manage assets and flows. The accounts are EOAs (Externally Owned Account).
dev-account-dashboard
There are [several use cases](/docs/guides/server/dev) for this: - **Treasury Account**: Transferring assets on demand. - **Minting Account**: Minting assets on demand. - **Escrow Account**: Hold assets or tokens in an escrow between players and transferring them afterwards. ## Requisites Developer account pay for gas using either: - **Support [ERC-2771](https://eips.ethereum.org/EIPS/eip-2771) transactions**: The assets you want to escrow need to support [ERC-2771](https://eips.ethereum.org/EIPS/eip-2771) transactions (i.e. gasless). - **Funding a backend wallet**: You need to fund your developer account with the chain's native token. ## Create a backend wallet Head to the [backend wallet](https://dashboard.openfort.xyz/accounts) page in your dashboard settings and click on `Add account`. By default, the backend wallets created with Openfort are custodial.
addDevAccount
```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const settings = await openfort.settings.createDeveloperAccount({ name: 'Minting Account', }) ``` ```bash command-line curl https://api.openfort.xyz/v1/settings/developer_accounts \ -u "$YOUR_SECRET_KEY:" \ -d name= "Minting Account" ```
### Verify wallet ownership If you're looking to **sponsor gas with your native tokens** for smart accounts, it's important to verify your deposited funds with the paymaster. Head to [backend wallets](https://dashboard.openfort.xyz/accounts) in your dashboard and click on `Add account`. 1. Click on "Advanced Options" to start the process. 2. Sign the explorer message. 3. Add the wallet address used to deposit native tokens. 4. Add the signed message.
noncustodial-dev-account
### Optional: Custom forwarder contract By default you can use the [supported forwarder contracts](/docs/addresses) from Openfort if you need. Alternatively, you can also use your forward contract in order to sponsor the transaction of your backend wallet. Go to your [Gas policy](https://dashboard.openfort.xyz/policies) section and create a policy by adding the address of your `Forwarder contract address`. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/ecosystem.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Ecosystem dashboard configuration', breadcrumb: 'Dashboard', } Creating ecosystem wallets is an **enterprise feature**. To enable it, please [contact us](https://t.me/joalavedra). Use the **customization** page of the dashboard to configure your ecosystem's brand settings, including name, logo, accent color, and legal policies.
whitelabel_dashboard
## Customization options | Customization | Description | | ------------- |-------------| | Domain | Choose where to host your dashboard | | Name | Ecosystem name as you'd like to present it to users | Logo | Ecosystem logo | | Brand color | Accent color for your ecosystem | | Legal | Used to set your own terms & conditions, and your privacy policy. | | SDK links | Client SDKs | | Example links | Template examples using the ecosystem SDKs | export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/external-auth.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Using a third-party auth provider', description: 'Integrate with existing auth providers and backends', subtitle: 'Learn how to integrate with third-party auth provider.', breadcrumb: 'Authentication', } Openfort's signer solution enables the user onboarding by integrating with established backend solutions and authentication providers that support JWT-based authentication. This strategy provides a trusted, scalable, and versatile framework that supports an extensive range of authentication options. ## Third-party auth platforms With this approach, Openfort is in charge of creating **embedded signers** on the and follow the necessary security steps to make sure the smart wallet created remains non custodial.
## Custom Auth Methods We offer two options to setup embedded signers with custom auth, one that is based on the OIDC ([Open ID Connect](https://openid.net/developers/how-connect-works/)) standard, and a generic option that lets you bring your own auth server.
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/faqs.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'faqs', title: 'FAQs', description: 'Most frequently asked questions about the Openfort platform.', } ### Can players use ERC-20 tokens to pay for gas fees? Yes, you can sponsor fully or partially with the network token or ERC-20. ### Do users need to fund the newly created accounts? You don't need to. With Openfort you can use policies to sponsor gas fees on behalf of your users. ### How do I pay for the sponsored gas fees? Openfort handles all the gas payments for you when using policies. While everything is free on `Testnets`, on `Mainnets` you'll need to top up your account. ### What smart contracts can I interact with? Yes, you're free to use any smart contracts you wish. You will need add contracts using the assets page in your dashboard. ### Is Openfort ERC-4337 compatible? Yes, Openfort is compatible with Account Abstraction (ERC-4337) among other standards and follows best practices and implementations across other ethereum standards. ### What blockchains do you support? Checkout the comprehensive list of [supported chains](/docs/chains). ### Can users have the same smart account address on all EVM chains? Yes, users can have the same address across all EVM chains because the addresses are deterministic. Each chain will have separate smart account. ### Has Openfort been audited? The Smart Account implementation has been [audited by CertiK](https://drive.google.com/drive/u/0/folders/1aoPgJD_oz1qagWflnO91ASlQo-2upjRL) and the embedded signer is [audited by Cure+53](https://drive.google.com/drive/u/0/folders/1aoPgJD_oz1qagWflnO91ASlQo-2upjRL). ### Do you provide the ability to communicate with players through notifications? Openfort can notify you of transactions succeeded or reverted with [webhooks](/docs/guides/dashboard/webhooks). You can use that to send push notifications. ### What's Openfort's business model? At Openfort we work with any size business to connect your backend and product to the blockchain. Our business model adapts to your needs based on volume as well as the revenue and growth model your business has. ### How can I activate "Live Mode"? Whenever you want to go live with your product, you need to make sure to complete the details on your billing settings. This is necessary on order to top up your Account Funds. ### What options are available for branding and white labeling? Openfort offers headless smart accounts which means that you can customize your own UI and experience. You can decide to use any popular framework or completely integrate it within you game (zero popups). ## Security and Contingency Planning ### If Openfort were to shut down with a one-month notice, would there be scope to change the signer on the Smart Contract Wallet and use it in connection with a different provider that manages the private keys differently? **TLDR:** With enough time, transitioning is fairly simple. You’d need to invoke the `transferOwnership` function for users to accept the new signer. **Detailed Answer:** Yes, if Openfort shuts down with a one-month notice, it's possible to change the signer. Since Openfort wallets are non-custodial, users have control over their private keys. The key migration process would involve using the "recovery share" and "device share" from Shamir's Secret Sharing (SSS) to reconstruct the private key, allowing users to accept a new signer through the `transferOwnership` function. The new provider would need to support compatible key management systems. ### If Openfort were shut down with zero notice, would there be any scope to do a migration? Would that rely on a self-hosted Shield for the recovery share and the device share being intact? **TLDR:** If there is no self-hosted option, users should rely on on-chain social recovery. **Detailed Answer:** Migration is still possible, but it depends on the self-hosted Shield for the recovery share and the availability of the device share. If a self-hosted Shield is not in place, users can utilize on-chain social recovery. As long as the device share and recovery share are intact, users can reconstruct their private key and migrate to a new provider. On-chain social recovery can also help recover the wallet if the device share is lost. ### If Openfort's API were compromised, what is the risk there? Can that risk be mitigated? What’s the risk of the auth share on the private key being exposed? **TLDR:** Both Openfort's server and Shield are encrypted. Even if an attacker obtains the auth share, they would need a secret to decrypt it. **Detailed Answer:** If Openfort's API were compromised, the risk is limited because both the auth share and Shield service are encrypted. Even if an attacker gains access to the auth share, they would still need to decrypt it using a secret. Furthermore, since the private key is split using Shamir's Secret Sharing, the auth share alone is insufficient to reconstruct the full key without the device or recovery share. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/gas-erc20.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import StepHikeCompact from '@/components/StepHikeCompact' import { Accordion } from '@/components/ui' export const meta = { title: 'Charge Gas Fees with ERC20 Tokens', description: 'Make your users pay transaction with ERC20.', subtitle: 'A step-by-step guide to configure gas fee payments using ERC20 tokens.' } Gas fees can be a hurdle for many users in blockchain applications. This guide will help you configure gasless transactions where the gas is paid using an ERC20 token. Choose between dynamic or fixed-rate payment strategies. By the end of this guide, you’ll have a working implementation for charging gas fees with ERC20 tokens and executing transactions seamlessly.
Charge an ERC20 with dynamic price} id="mint-nft" > {/* Step 1: Select Contract */}
  • Add your collectible’s smart contract.
  • Define the contract function you want to use (e.g., mint).
```bash command-line curl https://api.openfort.xyz/v1/contracts \ -u "$YOUR_SECRET_KEY:" \ -d 'name=NFT Contract' \ -d 'chainId=80002' \ -d 'address=contract_address' ```
Add Contract
{/* Step 2: Create a Dynamic ERC20 Policy */}
  • Create a new policy and select the strategy charge dynamic amount of ERC20.
  • Select the ERC20 token contract and exchange rate.
  • Link the imported contract and the function you want to sponsor.

If you want to update the dynamic rate programmatically, contact us.

```bash command-line curl https://api.openfort.xyz/v1/policies \ -u "$YOUR_SECRET_KEY:" \ -d 'name=My Policy' \ -d 'chainId=80002' \ -d 'strategy[sponsorSchema]=charge_custom_tokens' \ -d 'strategy[tokenContract]=con_...' \ -d 'strategy[tokenContractAmount]=1' ``` ```bash command-line curl https://api.openfort.xyz/v1/policies/:id/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="contract_functions" \ -d functionName="All functions" \ -d contract="con_..." ```
Dynamic Pricing Policy
{/* Step 3: Create a Gasless Transaction */}
  • Add chainId.
  • Add the contract.
  • Add the policy.
  • Add the function you want to interact with.

Note: You can make a transaction without a registered user or account deployed at the time of interaction. Once you make the transaction, a playerId and accountId will be created.

```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d 'chainId=80002' \ -d 'optimistic=true' \ -d 'policy=policy_id' \ -d 'interactions[0][contract]=contract_address' \ -d 'interactions[0][functionName]=mint' \ -d 'interactions[0][functionArgs][0]=sender_address_or_id' ```
{/* Optional Step 4: Add Account or Player */}
  • Add an account or player to specify the user.
```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d 'chainId=80002' \ -d 'policy=policy_id' \ -d 'account=account_id' \ -d 'optimistic=true' \ -d 'interactions[0][contract]=contract_address' \ -d 'interactions[0][functionName]=mint' \ -d 'interactions[0][functionArgs][0]=sender_address_or_id' ```
Charge an ERC20 with fixed prize} id="deploy" > {/* Step 1: Select Contract */}
  • Add your collectible’s smart contract.
  • Define the contract function you want to use (e.g., mint).
```bash command-line curl https://api.openfort.xyz/v1/contracts \ -u "$YOUR_SECRET_KEY:" \ -d 'name=NFT Contract' \ -d 'chainId=80002' \ -d 'address=contract_address' ```
Add Contract
{/* Step 2: Create a Fixed ERC20 Policy */}
  • Create a new policy and select the strategy charge fixed amount of ERC20.
  • Specify the ERC20 token contract and the fixed amount to charge.
  • Link the imported contract and the function you want to sponsor.
```bash command-line curl https://api.openfort.xyz/v1/policies \ -u "$YOUR_SECRET_KEY:" \ -d 'name=Fixed Policy' \ -d 'chainId=80002' \ -d 'strategy[sponsorSchema]=charge_fixed_rate' \ -d 'strategy[tokenContract]=contract_address' \ -d 'strategy[tokenContractAmount]=1' ```
Fixed Pricing Policy
{/* Step 3: Create a Gasless Transaction */}
  • Add chainId.
  • Add the contract.
  • Add the policy.
  • Add the function you want to interact with.

Note: You can make a transaction without a registered user or account deployed at the time of interaction. Once you make the transaction, a playerId and accountId will be created.

```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d 'chainId=80002' \ -d 'optimistic=true' \ -d 'policy=pol_...' -d 'interactions[0][contract]=con_...' \ -d 'interactions[0][functionName]=mint' \ -d 'interactions[0][functionArgs][0]=sender address or Id' ```
- Add account or add player ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d 'chainId=80002' \ -d 'policy=pol_...' \ -d 'account=acc...' or 'player=pla...' \ -d 'optimistic=true' \ -d 'interactions[0][contract]=con_...' \ -d 'interactions[0][functionName]=mint' \ -d 'interactions[0][functionArgs][0]=sender address or Id' ```
export const Page = ({ children }) => ( ) export default Page --- File: /pages/guides/dashboard/gas-sponsorship.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { Accordion } from '@/components/ui' export const meta = { title: 'Gas sponsorship', description: 'Gas sponsorship offers a flexible way to manage and control gas payments', subtitle: 'Gas sponsorship offers a flexible way to manage and control gas payments', breadcrumb: 'Dashboard', } Whether you're building a game, marketplace, or any web3 application, these policies give you the tools to create seamless user experiences by controlling how transaction fees are handled. ## What's a Gas Manager? A gas manager is at the heart of how Openfort handles transaction fees. Think of it as your control center for managing how and when your application will sponsor user's gas fees. You might use it to make onboarding smoother by covering gas fees for new users, let players use in-game tokens for transactions, or encourage specific actions in your ecosystem.
control policy spending
## Getting started Setting up gas sponsorship is straightforward. Start by visiting the [Gas Policy tab](https://dashboard.openfort.xyz/policies) in your dashboard and clicking `Add Policy`. From there, you'll be able to configure how you want to handle transaction fees. ## Sponsoring gas fees When it comes to sponsoring gas fees, you have two main approaches available: ### Paying with credit card The simplest way to get started is by adding [balance credit](https://dashboard.openfort.xyz/settings/project/billing) to your account. When you choose this method, gas costs are automatically deducted from your balance as transactions occur. This is particularly useful when you're ready to go live with your project, as it's required for `livemode` operations. ### Paying with native tokens For more advanced use cases, you can use network native tokens (like ETH on Base). This method involves depositing tokens to Openfort's Paymaster contract. Here's how to set it up: Check the [entity addresses](/docs/addresses) page to find the paymaster's address in your network. Tokens deposited in this contract can always be withdrawn by the owner and you can control its balance at any time checking the its balance. 1. First, deposit your tokens using the `depositFor` function:
deposit native tokens
2. After depositing, head to the [backend wallets](https://dashboard.openfort.xyz/accounts) page to register your EOA wallet. 3. Sign and validate your signature by clicking on advanced configuration (see the video below).
4. Finally, configure your policy to use these deposits by selecting "Sponsor gas with your tokens" when editing or creating a policy:
deposit native tokens
When using a strategy that supports payment in ERC-20 tokens (i.e. `charge_custom_tokens` or `fixed_rate`), the backend wallet will receive the tokens users pay for gas fees. ## Optional: Using external paymasters For those needing custom solutions, Openfort supports integration with external paymasters. This feature is particularly useful when you have specific requirements for gas sponsorship that go beyond the standard options. Note that when using external paymasters, you'll need to use the `pay_for_user` strategy. When using an external paymaster, the only supported `strategy` is `pay_for_user`. To set up an external paymaster, you can either use the dashboard:
Using external paymasters
Or configure it through the API: ```bash # Create the paymaster object curl https://api.openfort.xyz/v1/paymasters/ \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d address=80002 \ -d url="YOUR_PAYMASTER_URL" # Link it to your policy curl https://api.openfort.xyz/v1/policies/:id \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d paymaster=pay_... ``` With these fundamentals in place, you're ready to start managing gas fees for your users. The next section will dive deeper into the different types of policies and rules you can create. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/keys.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'API Keys', description: 'Use API keys to authenticate API requests.', subtitle: 'Use API keys to authenticate API requests.', breadcrumb: 'Dashboard', } ## Regenerate API keys Regenerating an API key will invalidate the current key and generate a new one. This action cannot be undone. If you have set up webhooks or registered a Shield project with the key, you will need to update them with the new key. Openfort supports the ability to regenerate, delete and create API keys. You can do this at any time in the [API keys](https://dashboard.openfort.xyz/developers/api-keys) section of the dashboard. - **Delete and regenerate API keys**:
generate-delete-api-keys
- **Generate new API keys**: You can create multiple API keys when you're planning to generate a new one to avoid disruption to your integration.
generate-api-keys
### Limit API keys interaction by IP Openfort supports limiting the IPs that can interact with Openfort services using specific APIn keys. To enable this, [API keys](https://dashboard.openfort.xyz/developers/api-keys) section of the dashboard and press the three dots next to the **secret key**. A new page will appear with an option `Whitelist IPs` like so:
generate-delete-api-keys
You can then add multiple IPs per single secret key. If you try to make a request from an unauthorized IP, you will receive a `Forbidden` error like so: ```json { "error": { "type": "invalid_request_error", "message": "Access is limited for this address" } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/notifications.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Events', description: 'Get notified about events happening in Openfort and onchain', subtitle: 'Get notified about events happening in Openfort and onchain.', breadcrumb: 'Dashboard', } ## Why use events? When building Openfort integrations, you might want your applications to receive events as they occur in your Openfort accounts, so that your backend systems can execute actions accordingly. You can configure notifications via the API to be notified about events that happen in your Openfort account or on-chain. By default, Openfort will send a notification to the specified subscriptions every 24 hours. ## Create an event Notification objects are the core of the event system. They define the name of the event and encapsulate both the trigger and subscriptions. ```bash command-line curl https://api.openfort.xyz/v1/notifications/ \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d "name=Low balance" ``` ```ts server.ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const notifications = await openfort.notifications.create({ name: "Low balance" }) ``` ```csharp Program.cs using Openfort.SDK; using Openfort.SDK.Model; const openfort = new OpenfortClient(YOUR_SECRET_KEY); const notifications = await openfort.Notifications.Create( new CreateNotificationRequest( name: "Low balance" ) ); ``` You can also configure events directly from your **dashboard**. ## Create a trigger Triggers define the condition that will trigger the notification. There are 3 available triggers: - **[Project balance trigger](https://dashboard.openfort.xyz/settings/project/notifications)**: Define a threshold balance of credits in your project. This is useful to control you can continue to sponsor gas fees for your users. - **[Contract balance trigger](https://dashboard.openfort.xyz/developers/events)**: Check for the returned parameter of a contract call and compare it to a threshold. This is useful to control the deposited amount in a paymaster contract. - **[Backend wallet balance trigger](https://dashboard.openfort.xyz/developers/events)**: Check for the balance of a backend wallet and compare it to a threshold. This is useful when you're using a backend wallet itself is paying for the gas fees of the transactions it puts onchain. There can be more than one notification trigger per event. ```bash command-line curl https://api.openfort.xyz/v1/notification_triggers \ -u "$YOUR_SECRET_KEY:" \ -d 'notification=not_e0b84653-1741-4a3d-9e91-2b0fd2942f60' \ -d 'type=project_balance_trigger' \ -d 'threshold=1000000000' ``` ```ts server.ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const notificationtriggers = await openfort.notificationTriggers.create({ notification: "not_e0b84653-1741-4a3d-9e91-2b0fd2942f60", type: "project_balance_trigger", threshold: "1000000000" }) ``` ```csharp Program.cs using Openfort.SDK; using Openfort.SDK.Model; const openfort = new OpenfortClient(YOUR_SECRET_KEY); const notificationtriggers = await openfort.NotificationTriggers.Create( new CreateNotificationTriggerRequest( notification: "not_e0b84653-1741-4a3d-9e91-2b0fd2942f60", type: "project_balance_trigger", threshold: "1000000000" ) ); ``` ## Create a subscription Subscriptions define the method and target of the event. There are 2 available subscription methods: - **Email**: Send an email to the specified target. - **Webhook**: Send a POST request to the specified target. To learn more about receiving webhooks, check out the [webhooks guide](/docs/guides/dashboard/webhooks) and the types `notification.developer_account.balance`, `notification.contract.balance` or `notification.project.balance`. There can be more than one notification subscription per event. ```bash command-line curl https://api.openfort.xyz/v1/notification_subscriptions \ -u "$YOUR_SECRET_KEY:" \ -d 'notification=not_e0b84653-1741-4a3d-9e91-2b0fd2942f60' \ -d 'method=Email' \ -d 'target=jaume@openfort.xyz' ``` ```ts server.ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const notificationsubscriptions = await openfort.notificationSubscriptions.create({ notification: "not_e0b84653-1741-4a3d-9e91-2b0fd2942f60", method: "Email", target: "jaume@openfort.xyz" }) ``` ```csharp Program.cs using Openfort.SDK; using Openfort.SDK.Model; const openfort = new OpenfortClient(YOUR_SECRET_KEY); const notificationsubscriptions = await openfort.NotificationSubscriptions.Create( new CreateNotificationSubscriptionRequest( notification: "not_e0b84653-1741-4a3d-9e91-2b0fd2942f60", method: "Email", target: "jaume@openfort.xyz" ) ); ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/project-billing.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'project-based-billing', title: 'How billing works', description: 'Learn how project-based billing works in Openfort.', subtitle: 'Learn how organzation-based billing works in Openfort.', } Our goal at Openfort is to provide a _predictable_ billing system that grows with your project. ## How billing is organized The Openfort Platform has "projects". A user can be a member of multiple projects. For example: - `User 1` - `Project 1` (Smart Accounts, Auth, Payments) - `Project 2` (Smart Accounts, Auth, Payments) - `User 2` - `Project 3` (Smart Accounts, Auth, Payments) ## Billing system ### Project-based Billing Each project has an individual subscription, a plan and addons. For example, `Project 1` could be on the Pro plan and `Project 2` could be on the Free plan. ![Credit Balance](https://blog-cms.openfort.xyz/uploads/project_billing_4f33e2d7a9.png) ### Credit balance (Prepaid) Each project has a credit balance. The credit balance is used to pay for the project's gas sponsorship. Given that each proct supports all chains, the credit balance is shared across all chains. You can monitor the gas report spending in by visiting the policy page. ![Policy Gas Reports](https://blog-cms.openfort.xyz/uploads/policy_report_de8f42695f.png) ### FAQ
Do you only support the prepaid option? No, we also support the postpaid option. Please contact us for more information at joan@openfort.xyx.
What happens if my balance reaches 0? Gas sponsorship will be disabled for your project. You can top up your balance to enable it again. If you want more flexible billing options, please contact us at joan@openfort.xyz, where we can enable a buffer for your project.
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/social-login.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Social Login', description: 'Logging in with social accounts', breadcrumb: 'Authentication', } OAuth is commonly used for things like logging in to a social media account from a third-party app. It is a secure and convenient way to authenticate users and share information between applications. ### Social Providers
## Provider Token You can use the provider token and provider refresh token returned to make API calls to the OAuth provider. For example, you can use the Google provider token to access Google APIs on behalf of your user. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/sponsor-rules.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { Accordion } from '@/components/ui' export const meta = { id: 'rules', title: 'Gas Policy Strategies & Rules', description: 'This guide covers the detailed configuration of gas policies, including available strategies and rule types', subtitle: 'Covers the detailed configuration of gas policies, including available strategies and rule types', breadcrumb: 'Dashboard', } ## Gas Policy Strategies Gas policies offer three distinct strategies for handling transaction fees:
PolicyGas
### 1. Sponsored Transactions Developers cover all gas fees, removing the need for users to hold native tokens.
PolicyERC20Payment
```bash curl https://api.openfort.xyz/v1/policies/ \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d chainId=80002 \ -d name="Sponsored Policy" \ -d "strategy[sponsorSchema]=pay_for_user" ```
### 2. Dynamic ERC20 Payment Users pay gas fees using ERC20 tokens at a dynamic exchange rate.
PolicyERC20Payment
```bash curl https://api.openfort.xyz/v1/policies/ \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d chainId=43113 \ -d name="Dynamic ERC20" \ -d "strategy[sponsorSchema]=charge_custom_tokens" \ -d "strategy[tokenContract]=con_..." \ -d "strategy[tokenContractAmount]=1" ```
### 3. Fixed ERC20 Payment Users pay a fixed amount of ERC20 tokens per transaction.
PolicyERC20Payment
```bash curl https://api.openfort.xyz/v1/policies/ \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d chainId=80002 \ -d name="Fixed ERC20" \ -d "strategy[sponsorSchema]=fixed_rate" \ -d "strategy[tokenContract]=con_..." \ -d "strategy[tokenContractAmount]=10000" ```
## Policy Rules While strategies determine how gas fees are paid, rules define when and how your gas policy applies. Every policy needs at least one rule to function, and you can choose from three types: | Rule Model | Description | |----------------------|--------------------------------------------------------| | **`contract_functions`** | Sponsor interactions with smart contracts. | | **`account_functions`** | Sponsor interactions with the smart account. | | **`limit_rules`** | Limit the amount of gas or number of transactions over an interval. | ### Contract functions These rules let you specify which smart contract interactions your policy covers. You might want to sponsor all interactions with your game contracts but not with external marketplaces, for instance. Wildcard policies allow you to sponsor any transaction for any contract without the need to add them in the policy. Enable "Catch-all sponsorship". Wildcard policy To create a policy rule, you need first to add a contract to Openfort:
Add a contract} id={`add-contract`} > If the contract is not verified on the block explorer, you will need to enter the ABI manually. If the contract you want to interact with is a proxy contract, you will need to enter the ABI of the implementation contract. Add a contract to Openfort to an API request: ```bash command-line curl https://api.openfort.xyz/v1/contracts \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d name="SimpleNFT" \ -d address="0x416c...354D" \ -d chainId="80002" ``` Add a new contract by clicking the `Add contract` button in the [Asset contracts](https://dashboard.openfort.xyz/assets) section, then enter: - The name of the contract (it can be any name you want; the name is only for identification purposes) - The network (`chainId`) where the smart contract is located. - The address of the contract. - The Application Binary Interface (ABI) of the contract (if not verified in the block explorer of that network).
DashboardAddContract
Once you've selected your contract, you can then choose what function you whish to enable sponsorship for. You can select `All functions` instead to allow sponsoring all functions in that specific contract.
policyRules
```bash command-line curl https://api.openfort.xyz/v1/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="contract_functions" \ -d functionName="mint" \ -d "contract=con_..." ```
### Account functions These rules cover account-related operations, such as transferring ownership of accounts, managing session keys, or deploying smart accounts. They're essential for maintaining smooth account management operations within your application.
Register Session key
```bash command-line curl https://api.openfort.xyz/v1/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="account_functions" ```
### Limit rule Limit rules help you control usage of your gas policy. You can set limits based on: | Rule Type | Description | Example Use Case | |-----------|-------------|-----------------| | Gas per Interval | Total gas limit in timeframe | 1000 WEI/minute | | Gas per Transaction | Gas limit per transaction | 100 WEI/transaction | | Count per Interval | Transaction count limit | 10 transactions/minute |
Register Session key
```bash command-line curl https://api.openfort.xyz/v1/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="rate_limit" \ -d functionName="gas_per_transaction" \ -d gasLimit="1000000" ```
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/team.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Manage teams', breadcrumbs: 'Dashboard' } Openfort provides granular **access controls** to manage permissions across your organizations. For each project, a user can have one of the following roles: - Owner - Administrator - Member A default project is created when you first sign in and you'll be assigned the **Owner** role. Each member can access everything under the project. Create a separate project if you need to restrict access to certain parts. ## Manage team members To invite others to collaborate, visit your project's team settings in the [Dashboard](https://dashboard.openfort.com/settings/project/members) to send an invite link to another user's email. The invite expires after 24 hours. If you're creating an ecosystem, head to the [ecosystem guide](/docs/guides/ecosystem). ### Permissions across roles [#permission-across-roles] The table below shows the corresponding permissions for each available role you can assign a team member in the Dashboard. | Permissions | Owner | Administrator | Member | | ----------------------- | ----------------------- | ----------------------- | ----------------------- | | **Members** | | Add an Administrator | | | | | Remove an Administrator | | | | | Add a Member | | | | | Remove a Member | | | | | Revoke an invite | | | | | Resend an invite | | | | | Accept an invite | | | | | **Billing** | | Read invoices | | | | | Read billing email | | | | | Read billing address | | | | | Update billing address | | | | | Read payment methods | | | | | Update payment methods | | | | | **Projects** | | Create a project | | | | ## Organization Overview The default organization structure at Openfort are split in different projects. Each project has their own API Keys, players, assets and billing configuration beign completely independent one another.
organization-architecture
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/users.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Players', breadcrumbs: 'Dashboard' } Use the **Players** page of the dashboard to manage all registered players in your Openfort application. ## Player table The **player table** displays all players that have been registered within Openfort for your selected application. This table only shows players who have been created through Openfort's systems, whether via direct authentication or through your application's integration. You can see important information including: - Provider used for authentication - API ID (unique identifier) - Creation date - Last sign-in timestamp The **player table** is paginated to display 10 players at a time. You can navigate through the list using the "Previous" and "Next" buttons at the bottom. The current view range is displayed (e.g., "Viewing 1 to 10 of 838 results"). ### Player details Clicking on a player's API ID opens the **player details** page, where you can see comprehensive information about the selected player, including: - Details - API ID - Description - Creation timestamp - Metadata - External User ID - Accounts - Chain (e.g., Polygon) - Wallet address - Status (Active/Inactive) - Creation date - Transactions View and manage player transactions, including asset transfers and NFT minting - Sessions Monitor and manage player authentication sessions for frictionless interactions ## Authentication The drawer displays session data such as when the user first logged into your app, when they were last seen in your app. Please note that the "Last seen" field is a rough approximation on the order of an hour from when the user was precisely last active in your app. If you're using a third-party authentication provider instead of Openfort's authentication solution, this section will remain empty, and you'll manage your authentication through your chosen provider's interface. ### Deleting users From the user drawer, you can delete a user if necessary. This is an irreversible and destructive action; if the user logs into your app again, they will have a new user's ID (`playerID`), will have to relink any formerly linked accounts, and will get a new embedded wallet address. **Please take extreme care when deleting users.** For security of user assets, Openfort does not delete the embedded wallet, and instead "soft deletes" it by disassociating it from the deleted user. If the user still has access to their login method and their wallet password, if they have set one, their wallet can be recovered after deletion. export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard/webhooks.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'webhooks', title: 'Webhooks', description: 'Listen for events on your Openfort account.', subtitle: 'Listen for events so your integration can automatically trigger reactions.', breadcrumb: 'Dashboard', } ## What is a webhook? Openfort uses webhooks to push real-time notifications to you about your transactions. All webhooks use HTTPS and deliver a JSON payload that can be used by your application. You can use webhook feeds to do things like: - Granting users a game item when a transaction is confirmed. - Store all transaction events in your own database for custom reporting/retention ## Steps to receive webhooks You can start receiving real-time events in your app using the steps: 1. Create a local endpoint to receive requests 2. Register your development webhook endpoint 3. Test that your webhook endpoint is working properly 4. Register your production webhook endpoint ## Webhook object The webhook object contains the following fields: ```json { "data": { "id": "tin_c502d628-5bb3-42f2-b8f5-62ba4d71df3a", "createdAt": 1689869074, "object": "transactionIntent", "etc":"..." }, "type": "transaction_intent.succeeded", "date": 1689869074 } ``` Where the `type` will be one of the following: - `transaction_intent.succeeded`: The transaction intent has arrived on-chain and is confirmed. - `transaction_intent.failed`: The transaction intent has arrived on-chain and is reverted. - `transaction_intent.cancelled`: The transaction intent parameters were not met. - `transaction_intent.broadcast`: The transaction intent was broadcasted. - `balance. project`: The project balance. - `balance.contract`: The contract balance. - `balance.dev_account`: The balance of your backend wallet. And the `data` will be a [transaction intent object](https://www.openfort.xyz/docs/reference/api/get-a-transaction-intent-object). ### Register your development webhook endpoint Register your publicly accessible HTTPS URL in the Openfort [dashboard](https://dashboard.openfort.xyz/webhooks). Then decide the type of webhook you want to receive. You can create a tunnel to your localhost server using a tool like [ngrok](https://ngrok.com/download). For example: https://8733-191-204-177-89.sa.ngrok.io/webhooks
transaction_intent-sign
### Test that your webhook endpoint is working properly Send a few test transactions to check that your webhook endpoint is receiving the events. You can specify the number of block confirmations you want to wait before getting notified of a transaction making it on chain. The default is 0 (i.e. as soon as the transaction arrives on chain). To do so, you need to include the `confirmationBlocks` body parameter when [creating the transaction intent](https://www.openfort.xyz/docs/reference/api/create-a-transaction-intent-object).
transaction_intent-sign
export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/configuration/branding.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Branding - Wallet SDK', breadcrumb: 'Ecosystem wallet', }
ecosystem-rainbow-kit
When instantiating the **Client SDK**, you can pass in the `appearance` object to customize the appearance of the wallet. For wallet discovery, it will use [EIP-6963](https://eips.ethereum.org/EIPS/eip-6963) to embedded your branding. The `appearance` object has the following properties: - **icon**: a data url schema, compliant with [RFC-2397](https://www.rfc-editor.org/rfc/rfc2397). - **logo**: a [URI](https://www.rfc-editor.org/rfc/rfc3986) pointing to an image. The image SHOULD be a square with 96x96px minimum resolution. - **name**: a human-readable local alias of the Wallet Provider to be displayed to the user on the DApp. (e.g. `Example Wallet Extension` or `Awesome Example Wallet`) - **reverseDomainNameSystem**: the Wallet MUST supply the `rdns` property which is intended to be a domain name from the Domain Name System in reverse syntax ordering such as `com.example.subdomain`. It’s up to the Wallet to determine the domain name they wish to use, but it’s generally expected the identifier will remain the same throughout the development of the Wallet. It’s also worth noting that similar to a user agent string in browsers, there are times where the supplied value could be unknown, invalid, incorrect, or attempt to imitate a different Wallet. Therefore, the DApp SHOULD be able to handle these failure cases with minimal degradation to the functionality of the DApp. When creating your **client SDK** you need to add the *ecosystem ID*. It can be found in their dashboard at the [settings section](https://dashboard.openfort.xyz/settings/project/overview). The *ecosystemWalletDomain* is the domain where your wallet UI is hosted. Therefore, when creating your wallet SDK, you can pass in the `appearance` object to customize the appearance of the wallet. ```ts index.ts // Set your ecosystem id. Remember to switch to your live secret key in production. // See your ecosystem id here: https://dashboard.openfort.xyz/settings/project/overview import { AppMetadata, Client } from '@openfort/ecosystem-js/client' class EcosystemWallet extends Client { constructor(appMetadata?: AppMetadata) { super({ appMetadata: appMetadata, baseConfig: { // URL where the UI wallet is hosted ecosystemWalletDomain: 'https://wallet.ecosystem.com', ecosystemId: 'YOUR_ECOSYSTEM_ID', }, appearance: { icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFwF52RAAAACXBIWXMAAAsTAAALEwEAmpwYAAABpElEQVQ4jZ2Sv0vDUBTFf4f9Cg', logo: 'https://www.example.com/logo.png', name: 'Ecosystem Wallet', reverseDomainNameSystem: 'com.example.ecosystem.wallet' } }); // Use a Proxy to allow for new method additions return new Proxy(this, { get: (target, prop) => { if (prop in target) { const value = target[prop as keyof EcosystemWallet]; return typeof value === 'function' ? value.bind(target) : value; } return undefined; } }); } setPolicy(options?: { policy?: string; }): void { return super.setPolicy(options); } } export default EcosystemWallet; ``` You can check all the available components in the [Client SDK reference](/docs/reference/ecosystem-js/modules/client.html). export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/configuration/ecosystem-id.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Onboard your ecosystem partners', breadcrumb: 'Ecosystem wallet', } After you've created your own ecosystem SDK and registered the npm package. You're now ready to onboard new projects and partners and let them use your new ecosystem wallet. Through the dashboard, you're able to create `child_projects` under your ecosystem, given it a name, and head to the members section to invite their emails.
ecosystem-architecture
----- Each child project will have their own API keys as well as capabilities to manage smart contracts, users, and gas policies. An ecosystem can decide to share multiple `contract_id` and `policy_id` with child projects in order to take advantage of gas policy campaigns or ecosystem assets like ERC20 tokens.
ecosystem-architecture
export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/configuration/login-methods.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Configure login methods', breadcrumb: 'Ecosystem wallet', } Openfort supports a variety of login methods for your app, including email, phone, wallet, Google, Apple, Twitter, Discord, Epic Games, Line, Telegram, and more coming. Users can either use these account types as their upfront login method, or can link them to their profile after logging in via a different method. ### 1. Configure _upfront_ login methods in the SDK The login methods you enable in the Openfort Dashboard should contain all of the account types that users are allowed to login with or link in your app. You can choose a subset (or all) of these account types as upfront login methods shown to users when they first login to your app. Learn more about configuring your authentication methods in the [auth guide](/docs/guides/dashboard/social-login). As soon as you enable each provider from your dashboard, it will automatically appear as an option in the authentication page. ## Using a custom auth provider ` Openfort's ecosystem wallets are fully-compatible with any authentication provider that supports JWT-based, stateless authentication. If you're looking to add embedded wallets to your app, you can either: - use Openfort as your authentication provider (easy to set up out-of-the-box). - use a custom authentication provider (easy to integrate alongside your existing stack). export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/configuration/samples.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Sample to create an ecosystem wallet SDK', breadcrumb: 'Ecosystem wallet', tocVideo: 'FBMv3LuGoG4', } The following is a sample and video guide on how to create a wallet SDK. ## Samples
{'A quick start guide to create your own wallet SDK with the ecosystem SDK'}
### Guides
export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/configuration/wallet-ui.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Craft and customize your wallet', breadcrumb: 'Ecosystem wallet', } The Fort **ecosystem wallets** come with a default set of screens for authentication, session key confirmation, sign typed message, configuration, and transaction confirmation. These screens are designed to be customizable to fit your brand and user experience. Openfort provides helpers to the most popular frameworks to make it easier to integrate the ecosystem wallets. The _default_ **Client SDK** expects the following routes to exist in your wallet UI: | Route | Description | |-----------------------|---------------------------| | /sign/personal-sign | personal_sign | | /sign/eth-sign-typed-data-v-4 | eth_signTypedData_v4 | | /sign/eth-send-transaction | eth_signTransaction | | /sign/eth-request-accounts | eth_requestAccounts | | /sign/wallet-show-calls | wallet_showCallsStatus | | /sign/wallet-send-calls | wallet_sendCalls | | /sign/eth-grant-permissions | wallet_grantPermissions | | / | Loading screen |
ecosystem-architecture
## React SDK When adding the React components to your App, there are two places where the components can be customized. All but one of the theme customizations options are passed through to the Fort Tailwind plugin in your `tailwind.config.js` file. In your **wallet UI project**, after installing the `@openfort/ecosystem-js` package to get started with the React SDK. It will be then available from `@openfort/ecosystem-js/react`. You can check all the available components in the [React SDK reference](/docs/reference/ecosystem-js/modules/react.html). Use the **live [ecosystem customization](https://build.openfort.xyz/)** tool to get your custom theme and components. ### Colors
UI-customization
The available colors are: **Background colors** - `bg000` - Lightest background color - `bg100` - Light background color - `bg200` - Medium background color **Border colors** - `border` - The color of borders **Button colors** - `btnPrimary` - The color of the primary button - `btnPrimaryText` - The text color for the primary button - `btnPrimaryHover` - The hover color for the primary button - `btnSecondary` - The color of the secondary button - `btnSecondaryText` - The text color for the secondary button - `btnSecondaryHover` - The hover color for the secondary button **Text colors** - `title` - The color for title text - `text` - The main text color - `textSubtle` - The color for subtle or secondary text **Status colors** - `info` - The color for informational elements - `success` - The color for success messages or indicators - `warning` - The color for warning messages or indicators - `error` - The color for error messages or indicators - `critical` - The color for critical messages or indicators These color variables can be used to customize various elements of the UI as shown in the image. For example, the main content area uses `bg200`, while the outer container uses `bg100`. Text elements use `title`, `text`, and `textSubtle` accordingly. The button styles (`btnPrimary`, `btnSecondary`, etc.) are applied to the "Approve" and "Deny" buttons at the bottom of the UI. ## Core SDK The **Core SDK** is the package that you will use to **receive and send** communication with the **Client SDK**. This package includes all the necessary functionality in order to onboard your users to blockchain with non-custodial wallets. ```ts main.ts // Set your publishable key, shield publishable key and ecosystem id. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys // See your ecosystem ID here: https://dashboard.openfort.xyz/settings/project/overview import { Core, MethodType } from "@openfort/ecosystem-js/core"; // Create a new instance of the Core SDK const core = new Core({ baseConfig: { publishableKey: "YOUR_PUBLISHABLE_KEY", supportedChains: [80002], ecosystemId: 'YOUR_ECOSYSTEM_ID', }, shieldConfig: { shieldPublishableKey: 'YOUR_SHIELD_PUBLISHABLE_KEY', }, oidcConfig: { redirectUri: "http://localhost:3000", }, }); // instantiate the event listener const evhl = core.eventsHandler; evhl.subscribe(MethodType.ACCOUNTS_REQUEST, (data) => { console.log("Event received", data); }) evhl.listen(); ``` This are the available **Method Types** that will be sent from the **Client SDK** and that you can subscribe to: | Method | Type | |-----------------------|---------------------------| | ETH_SEND_TRANSACTION | 'eth_signTransaction' | | ETH_TYPED_MESSAGE_V4 | 'eth_signTypedData_v4' | | PERSONAL_MESSAGE | 'personal_sign' | | WALLET_GRANT_PERMISSIONS | 'wallet_grantPermissions' | | WALLET_SEND_CALLS | 'wallet_sendCalls' | | WALLET_SHOW_CALLS_STATUS | 'wallet_showCallsStatus' | | ETH_REQUEST_ACCOUNTS | 'eth_requestAccounts' | You can check all the available components in the [Core SDK reference](/docs/reference/ecosystem-js/modules/core.html). You can react to receiving this events by subscribing to them and executing the necessary logic in your app, like rendering a confirmation screen or sending the transaction to the blockchain. export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/batch-transactions.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import StepHikeCompact from '@/components/StepHikeCompact' import { IconCheck } from '@/components/ui' export const meta = { title: 'Batch transactions', breadcrumb: 'Ecosystem wallet', hide_table_of_contents: true } Smart Wallet enables you to send multiple onchain calls in a single transaction, improving UX by reducing multi-step interactions to a single click. A common example is combining an ERC-20 `approve` with a swap operation. You can submit batch transactions using the new `wallet_sendCalls` [RPC](https://eip5792.xyz/reference/sendCalls) method. - First, verify if your app supports atomic batching (This step is crucial if your app supports multiple wallet types) - Use the `useCapabilities` hook from Wagmi experimental features - Implement fallback functionality for unsupported wallets Note: The `useWriteContracts` and `useCapabilities` hooks rely on new wallet RPC and may not be supported in all wallets. ```typescript app.tsx import { useCapabilities } from 'wagmi/experimental' function App() { const { data: capabilities } = useCapabilities() // Returns capability object per chain: // { // 84532: { // atomicBatch: { // supported: true, // }, // } // } // Check if atomic batching is supported in the chain we want to interact with const isAtomicBatchSupported = capabilities?.[84532]?.atomicBatch?.supported return (
{isAtomicBatchSupported ? ( ) : ( )}
) } ```
- Import required hooks: `useAccount` and `useWriteContracts` from Wagmi - Define your smart contract ABI - Initialize the `useWriteContracts` hook for batch transactions - Create a transaction handling function that can process multiple contract calls Important: Make sure your contract ABIs are correctly typed for better development experience. ```typescript app.tsx import { useAccount } from 'wagmi' import { useWriteContracts } from 'wagmi/experimental' // Define your contract ABI const abi = [ { stateMutability: 'nonpayable', type: 'function', inputs: [{ name: 'to', type: 'address' }], name: 'safeMint', outputs: [], } ] as const function BatchTransactionComponent() { const account = useAccount() const { writeContracts } = useWriteContracts() const handleBatchTransaction = () => { writeContracts({ contracts: [ { address: "0x119Ea671030FBf79AB93b436D2E20af6ea469a19", abi, functionName: "safeMint", args: [account.address], }, // Add more contract interactions as needed { address: "0x119Ea671030FBf79AB93b436D2E20af6ea469a19", abi, functionName: "safeMint", args: [account.address], } ], }) } return ( ) } ``` - Add the `useCallsStatus` hook to track transaction status - Configure polling interval for status updates - Display transaction status to users - Handle transaction completion and errors Pro tip: The polling interval can be adjusted based on your needs, but 1 second is a good default. ```typescript app.tsx import { useCallsStatus } from 'wagmi/experimental' function BatchTransactionComponent() { const { data: id, writeContracts } = useWriteContracts() const { data: callsStatus } = useCallsStatus({ id: id as string, query: { enabled: !!id, // Poll every second until confirmed refetchInterval: (data) => data.state.data?.status === "CONFIRMED" ? false : 1000, }, }) // Example response structure: // { // status: 'CONFIRMED', // receipts: [ // { // logs: [{ // address: '0x...', // topics: ['0x...'], // data: '0x...' // }], // status: 'success', // blockHash: '0x...', // blockNumber: 122414523n, // gasUsed: 390000n, // transactionHash: '0x...' // } // ] // } return (
{callsStatus && (

Status: {callsStatus.status}

{callsStatus.status === 'CONFIRMED' && (

Transaction confirmed! Hash: {callsStatus.receipts[0].transactionHash}

)}
)}
) } ```
export const Page = ({ children }) => {children} export default Page --- File: /pages/guides/ecosystem/create-wallet-button.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' import StepHikeCompact from '@/components/StepHikeCompact' export const meta = { title: 'Create wallet button', breadcrumb: 'Ecosystem wallet', } For the best onboarding experience, we recommend adding a highly visible 'Create' or 'Create Wallet' button to your app's homepage. Adding this button streamlines the onboarding experience for new users and gets them ready to use your app in a few seconds. Here is an example of how the button looks:
create-wallet-button
## Implementation with Wagmi To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. Using Wagmi offers a balanced approach that combines flexibility with developer convenience. By integrating the ecosystem wallet with Wagmi, you get access to a comprehensive set of React hooks that handle common wallet operations, state management, and chain interactions. This approach requires both `@rapidfire/id` and `Wagmi` dependencies, along with React Query, but provides a more structured development experience. While you'll still need to build your own UI components, Wagmi's hooks significantly reduce the complexity of handling wallet connections, transactions, and chain switching. First, set up your Wagmi configuration with the required chain and connector settings. ```ts wagmi.ts import { http, createConfig } from 'wagmi'; import { polygonAmoy } from 'wagmi/chains'; import { injected } from 'wagmi/connectors'; export const config = createConfig({ chains: [polygonAmoy], connectors: [ injected(), ], transports: { [polygonAmoy.id]: http(), }, }); declare module 'wagmi' { interface Register { config: typeof config; } } ``` Create a reusable wallet logo component that will be used in the button. ```tsx WalletLogo.tsx import React from 'react'; const defaultContainerStyles = { paddingTop: 2, display: 'flex', alignItems: 'center', }; export function WalletLogo({ size = 24, containerStyles = defaultContainerStyles, }) { return (
); } ```
Create the main button component using Wagmi's useConnect hook. ```tsx CreateWalletButton.tsx import React, { useCallback } from 'react'; import { useConnect } from 'wagmi'; import { WalletLogo } from './WalletLogo'; const buttonStyles = { background: 'linear-gradient(135deg, #2D3436 0%, #000000 100%)', border: '1px solid rgba(255, 255, 255, 0.1)', boxSizing: 'border-box' as const, display: 'flex', alignItems: 'center', gap: '12px', width: 'auto', minWidth: '200px', fontFamily: 'Inter, system-ui, sans-serif', fontWeight: '600', fontSize: '16px', color: '#FFFFFF', padding: '12px 20px', borderRadius: '12px', cursor: 'pointer', transition: 'all 0.2s ease-in-out', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', ':hover': { transform: 'translateY(-1px)', boxShadow: '0 6px 8px -1px rgba(0, 0, 0, 0.1), 0 4px 6px -1px rgba(0, 0, 0, 0.06)', }, }; export function CreateWalletButton() { const { connectors, connect, data } = useConnect(); const createWallet = useCallback(() => { const injectedConnector = connectors.find( (connector) => connector.id === 'injected' ); if (injectedConnector) { connect({ connector: injectedConnector }); } }, [connectors, connect]); return ( ); } ```
For more detail, view the [`useConnect` documentation](https://wagmi.sh/react/api/hooks/useConnect). Upon successful connection, account information can be accessed via [data](https://wagmi.sh/react/api/hooks/useConnect#data) returned from `useConnect`, or via [`useAccount`](https://wagmi.sh/react/api/hooks/useAccount). ## Implementation with EIP-1193 Provider The EIP-1193 Provider approach gives you the most granular control over your ecosystem wallet integration by directly using the SDK's Ethereum provider. This method requires only the `@rapidfire/id` package and allows you to build everything from scratch. You'll handle all wallet interactions through the standard `EIP-1193` provider interface, giving you complete flexibility in implementing wallet creation, connection flows, and transaction handling. While this approach requires more custom development work, it's ideal for applications that need specialized wallet interactions or want to minimize dependencies. To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. Create a new SDK instance with your application configuration. ```ts sdk.ts import EcosystemWallet from '@rapidfire/id'; // Initialize the SDK with required parameters export const sdk = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` Configure the Ethereum provider with chain and policy settings. Make sure to set up your `NEXT_PUBLIC_POLICY_ID` in your environment variables. ```ts provider.ts import { sdk } from './sdk'; // Configure the provider with chain and policy export const provider = sdk.getEthereumProvider({ policy: process.env.NEXT_PUBLIC_POLICY_ID }); ``` Create the button component that uses the configured provider. ```tsx CreateWalletButton.tsx import React, { useCallback } from 'react'; import { WalletLogo } from './WalletLogo'; import { provider } from './provider'; const buttonStyles = { background: 'linear-gradient(135deg, #2D3436 0%, #000000 100%)', border: '1px solid rgba(255, 255, 255, 0.1)', boxSizing: 'border-box' as const, display: 'flex', alignItems: 'center', gap: '12px', width: 'auto', minWidth: '200px', fontFamily: 'Inter, system-ui, sans-serif', fontWeight: '600', fontSize: '16px', color: '#FFFFFF', padding: '12px 20px', borderRadius: '12px', cursor: 'pointer', transition: 'all 0.2s ease-in-out', boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)', ':hover': { transform: 'translateY(-1px)', boxShadow: '0 6px 8px -1px rgba(0, 0, 0, 0.1), 0 4px 6px -1px rgba(0, 0, 0, 0.06)', }, }; export function CreateWalletButton({ handleSuccess, handleError }) { const createWallet = useCallback(async () => { try { const [address] = await provider.request({ method: 'eth_requestAccounts', }); handleSuccess(address); } catch (error) { handleError(error); } }, [handleSuccess, handleError]); return ( ); } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/faqs.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'faqs', title: 'FAQs', description: 'Most frequently asked questions about the Openfort platform.', } ### Can Openfort support my ecosystem's login system? Yes, Openfort's architecture is built to allow thousands of new gaming ecosystems flourish. You ecosystem can be added as an OAuth provider allowing your community to be recognized. ### What if I can't find my authentication provider in the documentation? No problem, let us know which provider you want to use and we'll get right into it. ### Can players use their existing wallets alongside Openfort Auth? Users can link existing wallets to their account. This allows you to store and share these wallet addresses with games via the SDK for read-only use. ### What level of support and Service Level Agreements (SLAs) are provided? At Openfort, we understand the significance of maintaining a high standard of service. Our Service Level Agreements (SLAs) reflect our commitment to providing a reliable, efficient, and safe environment for your operations. ## Security and Contingency Planning ### If Openfort were to shut down with a one-month notice, would there be scope to change the signer on the Smart Contract Wallet and use it in connection with a different provider that manages the private keys differently? **TLDR:** With enough time, transitioning is fairly simple. You’d need to invoke the `transferOwnership` function for users to accept the new signer. **Detailed Answer:** Yes, if Openfort shuts down with a one-month notice, it's possible to change the signer. Since Openfort wallets are non-custodial, users have control over their private keys. The key migration process would involve using the "recovery share" and "device share" from Shamir's Secret Sharing (SSS) to reconstruct the private key, allowing users to accept a new signer through the `transferOwnership` function. The new provider would need to support compatible key management systems. ### If Openfort were shut down with zero notice, would there be any scope to do a migration? Would that rely on a self-hosted Shield for the recovery share and the device share being intact? **TLDR:** If there is no self-hosted option, users should rely on on-chain social recovery. **Detailed Answer:** Migration is still possible, but it depends on the self-hosted Shield for the recovery share and the availability of the device share. If a self-hosted Shield is not in place, users can utilize on-chain social recovery. As long as the device share and recovery share are intact, users can reconstruct their private key and migrate to a new provider. On-chain social recovery can also help recover the wallet if the device share is lost. ### If Openfort's API were compromised, what is the risk there? Can that risk be mitigated? What’s the risk of the auth share on the private key being exposed? **TLDR:** Both Openfort's server and Shield are encrypted. Even if an attacker obtains the auth share, they would need a secret to decrypt it. **Detailed Answer:** If Openfort's API were compromised, the risk is limited because both the auth share and Shield service are encrypted. Even if an attacker gains access to the auth share, they would still need to decrypt it using a secret. Furthermore, since the private key is split using Shamir's Secret Sharing, the auth share alone is insufficient to reconstruct the full key without the device or recovery share. export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/gas-policies.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Sponsor transactions', breadcrumb: 'Ecosystem wallet', } One of the biggest UX enhancements unlocked by smart accounts is the ability for app developers to sponsor their users' transactions. If your ecosystem has a gas policy enabled, you can start sponsorship your user's transactions by using the `policy` in your [dashboard](https://dashboard.openfort.xyz/policies). To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. ### Use a policy when injecting your provider Sponsor all transactions that will be made with the injected provider. ```tsx app.tsx import { sdk } from './sdk' function App() { useEffect(() => { config.getEthereumProvider({policy: 'pol_...'}); }, []); return (
) } ``` ```ts sdk.ts import EcosystemWallet from '@rapidfire/id' // Initialize the SDK with required parameters export const sdk = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` ### Updating the policy Updating your policy is useful if you change chain and need to specify a different policy ID. ```tsx app.tsx import { sdk } from './sdk' function App() { useEffect(() => { config.setPolicy({policy: 'pol_...'}); }, []); return (
) } ``` ```ts sdk.ts import EcosystemWallet from '@rapidfire/id' // Initialize the SDK with required parameters export const sdk = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` ----- You can also configure your own app level policy. Check the details in the [dashboard section](/docs/guides/dashboard/gas-sponsorship). - Using an [**external paymaster** setup.](/docs/guides/dashboard/gas-sponsorship#optional-using-external-paymasters) - Learn how to [use **erc20 tokens**](/docs/guides/dashboard/gas-erc20) to pay for gas fees. export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/getting-started.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Quickstart your wallet', breadcrumb: 'Ecosystem wallet', } This guide and the `configuration` sections are to help developers launch their own ecosystem wallet. If you're looking to use an existing ecosystem wallet SDK, please refer to the `usage` section and install the specific ecosystem package. The [**Fort SDK**](https://www.npmjs.com/package/@openfort/ecosystem-js) is the easiest way to create you ecosystem wallet. It comes with a [code-splitting environment](https://developer.mozilla.org/en-US/docs/Glossary/Code_splitting), all the necessary tools to make **your wallet SDK** a reality. It is the easier way to create your own ecosystem wallet. The Fort SDK has **two main parts**: 1. `@openfort/ecosystem-js/client`: The **Client SDK** that you will use to create your wallet SDK. 2. `@openfort/ecosystem-js/core`: The **Core SDK** that you will use to create your wallet UI. Fort also includes a React specific package `@openfort/ecosystem-js/react` that you can use to get started faster. ## 0. Requirements Your project will need some specific configuration to enable code splitting: - [Typescript version 5.0.2](https://github.com/microsoft/TypeScript/releases/tag/v5.0.2) or higher. - TS Config needs to have `compilerOptions.moduleResolution` set to `bundler`. - Your code editor and project should have the same version of Typescript. ## 1. Install the ecosystem SDK Install the latest version of [Fort SDK](https://www.npmjs.com/package/@openfort/ecosystem-js) using your package manager of choice: You will need to install `@openfort/ecosystem-js` at both your wallet SDK and wallet UI projects. ```sh Terminal npm install @openfort/ecosystem-js ``` ```sh Terminal yarn add @openfort/ecosystem-js ``` ## 2. Set your auth providers Navigate to the **auth providers** page on the [Openfort dashboard](https://dashboard.openfort.xyz) by selecting your project and then clicking Auth providers Methods in the side bar in the [players page](https://dashboard.openfort.xyz/players). Select the account types you'd like users to be able to login with. For more information on how to enable social logins, check out the [dashboard docs](/docs/guides/dashboard/social-login). ## 3. Get your Openfort API keys From the [Openfort Dashboard](https://dashboard.openfort.xyz) for select your desired app, navigate to the [developers page](https://dashboard.openfort.xyz/developers/api-keys) in the top bar. On the de tab, find the API keys section. Get your Openfort API keys, you will need it in the next step. You will find two keys: - **Publishable Key**: This value can be safely exposed in a client-side environment. - **Secret Key**: This value should never be exposed in a client-side environment. It should be kept secure and used only in a server-side environment. Learn more on how to use it in the [server-side guide](/docs/guides/server). You can [further secure it](/docs/guides/dashboard/keys) for production applications. To generate non custodial wallets, you will need to create a Shield instance. At the [API keys page](https://dashboard.openfort.xyz/developers/api-keys), scroll down to the Shield section and click on the **Create Shield keys** button. A **one time pop-up** will appear with a variable called **encryption share**. Its very important that you store it safely. You will not be able to see it again. Then, in your page, you will see two Shield keys: - **Publishable Key**: This value can be safely exposed in a client-side environment. - **Secret Key**: This value should never be exposed in a client-side environment. ## 4. Creating your wallet SDK
fort-architecture-1
The easiest way to get started is to create a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) object in order to map the already provided functionality of the **Client SDK**. You can nevertheless change or add new methods to fit your needs. When creating your **client SDK** you need to add the *ecosystem ID*. It can be found in their dashboard at the [settings section](https://dashboard.openfort.xyz/settings/project/overview). The *ecosystemWalletDomain* is the domain where your wallet UI is hosted. ```tsx main.ts // See your ecosystem id here: https://dashboard.openfort.xyz/settings/project/overview import { AppMetadata, Client } from "@openfort/ecosystem-js/client"; class EcosystemWallet extends Client { constructor(appMetadata?: AppMetadata) { super({ baseConfig: { ecosystemWalletDomain: 'https://id.sample.openfort.xyz', ecosystemId: 'test-226353cd-dd0e-4fba-8208-58dfe29d3581', }, appMetadata, }); return new Proxy(this, { get: (target, prop) => { if (prop in target) { const value = target[prop as keyof EcosystemWallet]; return typeof value === 'function' ? value.bind(target) : value; } return undefined; } }); } } export default EcosystemWallet; ``` ```json package.json { "name": "@ecosystem/wallet", "version": "0.0.1", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", "exports": { ".": { "import": "./dist/index.mjs", "require": "./dist/index.js", "types": "./dist/index.d.ts" } }, "scripts": { "build": "tsup src/index.ts --format cjs,esm --dts", "prepublishOnly": "npm run build" }, "keywords": [], "author": "Openfort (https://www.openfort.xyz)", "devDependencies": { "@types/node": "^20.4.5", "tsup": "^7.1.0", "typescript": "^5.6.2" }, "dependencies": { "@openfort/ecosystem-js": "0.0.13" }, "files": [ "dist" ] } ``` ```json tsconfig.json { "compilerOptions": { "target": "ES2022", "module": "ESNext", "moduleResolution": "bundler", "lib": ["ES2022", "DOM"], "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "resolveJsonModule": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.spec.ts"] } ``` You're all set! By running the `build` script you'll get a `dist` folder with the compiled code. You can now publish your package to [npm](https://www.npmjs.com/) and share it with the world. You can check all the available client methods in the [Client SDK reference](/docs/reference/ecosystem-js/classes/client.Client.html). ## 5. Creating your wallet UI The **wallet UI** is where your users will interact with your wallet.
fort-architecture-2
Openfort `@openfort/ecosystem-js` comes with a set of pre-built components that you can use to create your wallet UI. To learn how to customize it further, head to the [UI screens guide](/docs/guides/ecosystem/configuration/wallet-ui). In your project, import the **FortProvider** component and wrap your app with it. Set the **publishable key** field to you got from the Dashboard in step 3. Concretely, the `FortProvider` must wrap any component or page that will use the Fort SDK in your react app. It is generally recommended to render it as close to the root of your application as possible. For example, in a [NextJS](https://nextjs.org/) or [Create React App](https://create-react-app.dev/) project, you may wrap your components like so: ```tsx App.tsx // Set your publishable key, shield publishable key and ecosystem id. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys // See your ecosystem ID here: https://dashboard.openfort.xyz/settings/project/overview import { WalletGrantPermissions, WalletSendCalls, EthRequestAccounts, AppState, EthSendTransaction, EthSignTypedDataV4, FortProvider, PersonalSign, withAuthenticationRequired, Settings, UnsupportedMethod, WalletShowCalls, darkFortTheme } from '@openfort/ecosystem-js/react'; import { Route, Routes, useNavigate } from 'react-router-dom'; async function getShieldSession(accessToken:string):Promise { const response = await fetch(`${process.env.REACT_APP_BACKEND_URL!}/api/protected-create-encryption-session`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${accessToken}` } }); if (!response.ok) { throw new Error('Failed to fetch shield session'); } const data = await response.json(); return data.session; } const ProtectedRoute = ({ component, ...args }: any) => { const Component = withAuthenticationRequired(component, { onRedirecting: () => , }); return ; }; export default function Providers({children}: {children: React.ReactNode}) { const nav = useNavigate() return ( nav((appState && appState.returnTo) || window.location.pathname)} publishableKey={process.env.REACT_APP_OPENFORT_PUBLIC_KEY!} ecosystemId={process.env.REACT_APP_OPENFORT_ECOSYSTEM_ID!} shieldConfig={{ shieldPublishableKey: process.env.REACT_APP_SHIELD_PUBLIC_KEY!, getShieldSession: getShieldSession }} > } /> } /> } /> } /> } /> } /> } /> } /> } /> } /> ); } ``` ```tsx Loading.tsx import React from 'react'; const Loading: React.FC = () => { return (
Loading...
); }; export default Loading; ```
Check all the available core methods in the [Core SDK reference](/docs/reference/ecosystem-js/classes/core.Core.html). {/*
ecosystem-architecture
*/} {/* Security Considerations The Openfort SDK ensures secure transactions using the following mechanisms: - **SignableHash**: All transactions are represented by a `signableHash`, ensuring the integrity of each user action. - **Access Tokens**: Authenticated via trusted third-party providers to ensure user identity is securely managed. */} {/* ### 2. Set your login methods ### 3. Get your Openfort ecosystem ID ### 4. Import Fort into your app ### 5. Use Fort! */} export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/intro.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'The Wallet Framework for Chains.', breadcrumb: 'Ecosystem wallet', tocVideo: 'pzMm86rmC3w', } The Ecosystem Wallet Framework represents a comprehensive solution for enterprises and developers seeking to implement robust, scalable wallet infrastructure across their blockchain ecosystem. This framework addresses the complexities of wallet architectures while maintaining enterprise-grade security and seamless integration capabilities.
Picture of ecosystems and wallet
## Why we built this Let's be honest - building a smart wallet system from the ground up is no walk in the park. You've got to juggle quite a few balls: setting up authentication, picking the right smart contracts for accounts, implementing signers for ownership, and getting all the infrastructure ready for transaction sponsorship and bundling. Phew! Sure, you could use a third-party provider to handle all this, but here's the tricky part: it needs to be flexible enough to adapt to your needs while still having as little vendore lock-in to integrate. And let's not forget about the developer experience - because nobody wants to spend weeks just figuring out how to implement a wallet system. ### What's in the box? Here's the cool stuff you get with the Ecosystem SDK: - **User Management**: Think of it as your bouncer - keeping track of who's who and making sure only the right people get in - **Smooth Wallet Onboarding**: We make it super easy for users to get started with their wallets, add funds, and jump right in - **Your Wallet, Your Rules**: Want to make it look and feel like your own? No problem! You've got full control through our whitelabel dashboard and customizable packages - **Works Everywhere**: Whether you're building on Unity, Unreal Engine, or browsers, we've got you covered ### How it all fits together The Ecosystem SDK is built like a well-organized kitchen, with three main stations: 1. **Developer Integration Layer**: Where you cook up your integration 2. **Client-Wallet Communication**: The service window where orders (transactions) get passed 3. **Blockchain Interaction**: Where the magic happens on the blockchain
Ecosystem SDK architecture
## The main ingredients ### Client SDK (`@openfort/ecosystem/client`) Think of this as your head chef - it runs the show. It handles everything from creating your custom wallet SDK to managing pop-ups and transactions. The best part? It lives right in your app's front-end and can wear your brand's colors. It even comes with built-in security features and plays nice with all the popular blockchain tools. The Client SDK is EIP-1193 compatible, so it works great with popular tools like [viem](https://viem.sh)! ### Communication Module (`@openfort/ecosystem/core`) This is your maitre d' - making sure everything flows smoothly between your client and the wallet. It helps new users get set up with their non-custodial wallets and works in any browser environment. Need more details? Check out our [wallet guide](/docs/guides/wallets). ### Framework Prefabs These are like your ready-to-use recipe cards. We've got special helpers for different frameworks, including a really nice setup for [React](https://react.dev/) (`@openfort/ecosystem/react`). And yes, you can customize all the components to match your style! ## "But why not just use embedded wallets?" Good question! While embedded wallets might seem simpler at first glance, they can actually create quite a headache when you're working across an ecosystem. Here's why: ### The Embedded Wallet setup Picture this: every single app needs its own separate setup - installing packages, generating keys in iframes, handling authentication... It's like having to build a new kitchen for every restaurant in your chain!
embedded wallets with apps
### The Not-So-Fun parts of embedded wallets 1. **Authentication gets messy** - Every app needs its own bouncer (authentication system) - OAuth2 providers get confused when trying to share wallet access - There's no good way to keep track of who's logged in where 2. **Less control than you'd like** - Your partners need access to the master keys (Admin credentials) - It's harder to keep track of who's spending what - No central control room for permissions 3. **More work for everyone** - Each partner has to figure out their own wallet setup - More chances for security slip-ups - No easy way to see what's happening across all apps ## Why the Ecosystem SDK is better
ecosystem wallet with apps
What you get: - One login system that works everywhere (no more authentication headaches!) - Control all permissions from one place - A slick dashboard with your brand to onboard projects - Paymasters and smart accounts by default - One solid security setup for everything
export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/libraries.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Integrating with wallet connectors', breadcrumb: 'Ecosystem wallet', } Using a **wallet library** provides the most streamlined path to implementing a wallet UI, offering a complete solution with pre-built UI components and a polished user experience out of the box. This approach builds on top of Wagmi and includes additional UI components like the `ConnectButton`, ready-to-use themes, and built-in transaction interfaces. While it requires the most dependencies (`@rapidfire/id`, `Wagmi`, `React Query`, and `RainbowKit` -for example), it significantly reduces development time by providing a complete wallet interface solution. To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. ## Getting an EIP-1193 provider All of Ecosystem SDK wallets can export a standard [EIP-1193 provider](https://eips.ethereum.org/EIPS/eip-1193) object. This allows your app to request signatures and transactions from the wallet, using familiar JSON-RPC requests like `personal_sign` or `eth_sendTransaction`. [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193), also known as the Ethereum JavaScript API, is a standardized interface for how applications can request information, signatures, and transactions from a connected wallet. To get a wallet's EIP-1193 provider, use the `getEthereumProvider` method: ```tsx main.tsx import { ecosystemWalletInstance } from "./rapidfireConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = await ecosystemWalletInstance.getEthereumProvider(); ``` ```ts rapidfireConfig.ts import EcosystemWallet from '@rapidfire/id'; export const ecosystemWalletInstance = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` When requesting signatures and transactions from the wallet, you can either choose to interface with the **EIP-1193** provider directly, or to pass it to a library like `wagmi` or `viem`. If you want to check out the sample using the `@rapidfire/id` directly, you can find it in the [Rapidfire SDK repository](https://github.com/openfort-xyz/ecosystem-sample/tree/main/ecosystem-sdk/sdk-sample). You will see it includes examples using [ethers](https://docs.ethers.org/v5/), [connectKit](https://docs.family.co/connectkit), [rainbowKit](https://www.rainbowkit.com/) and [wagmi](https://wagmi.sh/). ## Implementation with RainbowKit
ecosystem-rainbow-kit
### 1. Install dependencies Install the `@rapidfire/id` SDK and its peer dependencies: ```bash npm i @rapidfire/id @rainbow-me/rainbowkit @tanstack/react-query ``` ### 2. Create the connector ```ts config.ts import EcosystemWallet from '@rapidfire/id'; export const identityInstance = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` ### 3. Wrap app with providers At the highest level of your applications, wrap the component with the wagmi, QueryClient, and RainbowKit providers. Pass the configuration you created in step 2 to the wagmi provider. All of **ecosystem wallets** can export a standard [EIP-1193 provider](https://eips.ethereum.org/EIPS/eip-1193) object. This allows your app to request signatures and transactions from the wallet, using familiar JSON-RPC requests like `personal_sign` or `eth_sendTransaction`. [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193), also known as the Ethereum JavaScript API, is a standardized interface for how applications can request information, signatures, and transactions from a connected wallet. To get a wallet's EIP-1193 provider, use the `getEthereumProvider` method: ```tsx _app.tsx import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; import {WagmiProvider} from 'wagmi'; import {polygonAmoy} from 'wagmi/chains'; import {useEffect} from 'react'; import {config} from './wagmiConfig'; import {identityInstance} from './config'; const queryClient = new QueryClient(); export default function App() { useEffect(() => { if (!identityInstance) return; identityInstance.getEthereumProvider(); }, []); return ( ); } ``` ```ts wagmiConfig.ts import {http, createConfig} from 'wagmi'; import {polygonAmoy} from 'wagmi/chains'; import {injected} from 'wagmi/connectors'; export const config = createConfig({ chains: [polygonAmoy], connectors: [injected()], transports: { [polygonAmoy.id]: http(), }, }); ``` ```ts config.ts import EcosystemWallet from '@rapidfire/id'; export const identityInstance = new EcosystemWallet({ appChainIds: [80002], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` ### 4. Use the `ConnectButton` Import the `ConnectButton` and use to prompt users to connect to their provider **ecosystem wallet**. ```tsx import {ConnectButton} from '@rainbow-me/rainbowkit'; function Page() { return (

My app

...
); } ``` Thats it! You can now use any wagmi hook in your application to interact with the connected wallet. When users connect and transact with their wallet, Openfort will open a pop-up for users to authorize any actions. export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/react-native-integration.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Create a React Native App', breadcrumb: 'Ecosystem wallet', } To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. This guide will walk you through adding support for any **ecosystem wallet** into a React Native app by integrating the [Mobile Wallet Protocol Client](https://www.npmjs.com/package/@mobile-wallet-protocol/client). If you need a template or scaffold to start with, you can check out the [Ecosystem Wallet Expo Example](https://github.com/openfort-xyz/ecosystem-wallet-expo-example). ## Prerequisites ### Install peer dependencies The Mobile Wallet Protocol Client library requires the [Expo WebBrowser](https://docs.expo.dev/versions/latest/sdk/webbrowser/) and [Async Storage](https://react-native-async-storage.github.io/async-storage/docs/install) packages to be installed. Follow the instructions on the respective pages for any additional setup. ```zsh [npm] npm i expo expo-web-browser @react-native-async-storage/async-storage ``` ```zsh [yarn] yarn add expo expo-web-browser @react-native-async-storage/async-storage ``` ### Polyfills Mobile Wallet Protocol Client requires `crypto.randomUUID`, `crypto.getRandomValues`, and `URL` to be polyfilled globally since they are not available in the React Native environment. Below is an example of how to polyfill these functions in your app using the [expo-crypto](https://docs.expo.dev/versions/latest/sdk/crypto/) and [expo-standard-web-crypto](https://github.com/expo/expo/tree/master/packages/expo-standard-web-crypto/) packages. ```zsh [npm] npm i expo-crypto expo-standard-web-crypto react-native-url-polyfill ``` ```zsh [yarn] yarn add expo-crypto expo-standard-web-crypto react-native-url-polyfill ``` ```js [polyfills.js] import "react-native-url-polyfill/auto"; import { polyfillWebCrypto } from "expo-standard-web-crypto"; import { randomUUID } from "expo-crypto"; polyfillWebCrypto(); crypto.randomUUID = randomUUID; ``` ```tsx [App.tsx] import "./polyfills"; // import before @mobile-wallet-protocol/client /// ... ``` ## Setup ### Install Mobile Wallet Protocol Client Add the latest version of Mobile Wallet Protocol Client to your project. ```zsh [npm] npm i @mobile-wallet-protocol/client@latest ``` ```zsh [yarn] yarn add @mobile-wallet-protocol/client@latest ``` ## Usage Mobile Wallet Protocol Client provides 2 interfaces for mobile app to interact with the Smart Wallet, an EIP-1193 compliant provider interface and a wagmi connector. If your app is using wallet aggregator, go straight to **Option 2: Wagmi Connector** for 1-line integration. :) ### Option 1: EIP-1193 Provider Create a new `EIP1193Provider` instance, which is EIP-1193 compliant. ```tsx [App.tsx] import { EIP1193Provider } from "@mobile-wallet-protocol/client"; // Step 1. Initialize provider with your dapp's metadata and target wallet const metadata = { name: "My App Name", customScheme: "myapp://", // only custom scheme (e.g. `myapp://`) is supported in v1.0.0 chainIds: [8453], logoUrl: "https://example.com/logo.png", }; const provider = new EIP1193Provider({ metadata, wallet: { type: 'web', name: "Rapid fire wallet", scheme: 'https://id.sample.openfort.xyz', iconUrl: 'https://purple-magnificent-bat-958.mypinata.cloud/ipfs/QmfQrh2BiCzugFauYF9Weu9SFddsVh9qV82uw43cxH8UDV', }, }); // ... // 2. Use the provider const addresses = await provider.request({ method: "eth_requestAccounts" }); const signedData = await provider.request({ method: "personal_sign", params: ["0x48656c6c6f20776f726c6421", addresses[0]], }); ``` ### Option 2: Wagmi Connector Add the latest verion of Mobile Wallet Protocol wagmi-connectors to your project. ```zsh [npm] npm i @mobile-wallet-protocol/wagmi-connectors@latest ``` ```zsh [yarn] yarn add @mobile-wallet-protocol/wagmi-connectors@latest ``` Simply import the `createConnectorFromWallet` function and pass in the wallet you want to use to wagmi config. ```ts [config.ts] import { createConnectorFromWallet, Wallets, } from "@mobile-wallet-protocol/wagmi-connectors"; const metadata = { name: "My App Name", customScheme: "myapp://", // only custom scheme (e.g. `myapp://`) is supported in v1.0.0 chainIds: [8453], logoUrl: "https://example.com/logo.png", }; export const config = createConfig({ chains: [base], connectors: [ createConnectorFromWallet({ metadata, wallet: { type: 'web', name: "Rapid fire wallet", scheme: 'https://id.sample.openfort.xyz', iconUrl: 'https://purple-magnificent-bat-958.mypinata.cloud/ipfs/QmfQrh2BiCzugFauYF9Weu9SFddsVh9qV82uw43cxH8UDV', }, }), ], transports: { [base.id]: http(), }, }); ``` Then you can use wagmi's react interface to interact with the Smart Wallet. ```tsx [App.tsx] import { useConnect } from "wagmi"; // ... const { connect, connectors } = useConnect(); return ( {signature && (

Signature: {signature}

)} {error &&
Error: {error.message}
}
) } ``` ## Typed Data Signing For more complex signatures, you can use typed data signing (EIP-712) with wagmi's `useSignTypedData` hook: ```tsx import { useSignTypedData } from 'wagmi' function SignTypedData() { const { signTypedData, data: signature, isPending, error } = useSignTypedData() const types = { Mail: [ {name: 'from', type: 'Person'}, {name: 'to', type: 'Person'}, {name: 'content', type: 'string'}, ], Person: [ {name: 'name', type: 'string'}, {name: 'wallet', type: 'address'}, ], } const handleTypedMessage = () => { signTypedData({ domain: { chainId: 1, // Replace with your chain ID name: 'Example DApp', verifyingContract: '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC', version: '1', }, types, message: { from: { name: 'Alice', wallet: '0x2111111111111111111111111111111111111111' }, to: { name: 'Bob', wallet: '0x3111111111111111111111111111111111111111' }, content: 'Hello!', }, primaryType: 'Mail', }) } return (
{signature && (

Signature: {signature}

)} {error &&
Error: {error.message}
}
) } ``` Both signing methods work seamlessly with Smart Contract Wallets that implement EIP-1271, allowing for a consistent signing experience across EOA and Smart Contract Wallets. export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem/web-app-wagmi.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import StepHikeCompact from '@/components/StepHikeCompact' import { IconCheck } from '@/components/ui' export const meta = { title: 'Wagmi template to create a web app', breadcrumb: 'Ecosystem wallet', } The following is a quick and easy implementation for getting started with [Wagmi](https://wagmi.sh/) template and the ecosystem wallet of choice. To make these instructions concrete, we have created a sample ecosystem wallet called **Rapidfire ID**. To interact with it, you can find its SDK in the NPM package directory: [@rapidfire/id](https://www.npmjs.com/package/@rapidfire/id). You can check out the GitHub [repository for Rapidfire Wallet](https://github.com/openfort-xyz/ecosystem-sample) to learn how to create your own wallet. This guide will walk you through integrating the ecosystem wallet Rapidfire ID. If you need a template or scaffold to start with, you can check out the [Rapidfire Wagmi Example](https://github.com/openfort-xyz/ecosystem-sample/tree/main/ecosystem-sdk/sdk-sample). - Run the project creation command using your preferred package manager - Follow the CLI prompts to set up your project ```bash terminal npm create wagmi ``` - Install all required dependencies - Start the development server - Your app should now be running on localhost ```bash terminal npm install @rapidfire/id npm install npm run dev ``` - Update the Wagmi configuration file. - Set up `polygonAmoy` as the primary chain. - Configure wallet connector with injected wallet preference. ```ts wagmi.ts import { http, createConfig } from 'wagmi'; import { polygonAmoy } from 'wagmi/chains'; import { injected } from 'wagmi/connectors'; export const config = createConfig({ chains: [polygonAmoy], connectors: [ injected(), ], transports: { [polygonAmoy.id]: http(), }, }); declare module 'wagmi' { interface Register { config: typeof config; } } ``` Wrap your app in the `WagmiProvider` React Context Provider and pass the **config** you created earlier to the **value** property. ```tsx app.tsx import { WagmiProvider } from 'wagmi' import { config } from './config' function App() { useEffect(() => { config.getEthereumProvider(); }, []); return ( {/** ... */} ) } ``` ```ts config.ts import EcosystemWallet from '@rapidfire/id' // Initialize the SDK with required parameters export const config = new EcosystemWallet({ appChainIds: [84532], appLogoUrl: 'https://a.rgbimg.com/users/b/ba/barunpatro/600/mf6B5Gq.jpg', appName: 'Example App', }); ``` You can find everything you need here: https://wagmi.sh/react/api/hooks export const Page = ({ children }) => {children} export default Page --- File: /pages/guides/javascript/auth/user-management/linking.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Linking & unlinking accounts', description: 'Linking additional accounts', breadcrumb: 'Authentication', subtitle: 'Manage the identities associated with your user.', } The user identity represents an authentication method associated to the user. For example, if a user signs in using their email, an email identity will be associated with the user. Developers can use Openfort to prompt users to link additional accounts (such as a wallet or Discord profile) at any point in their user journey, not just during login. ## Linking accounts ### Link email Links an email and password to an existing account using an authentication token. ```tsx auth.tsx import openfort from "./openfortConfig" const email = 'EMAIL'; const password = 'PASSWORD'; const authToken = 'YOUR_USER_AUTH_TOKEN'; async function linkEmailPassword() { await openfort.linkEmailPassword({email, password, authToken}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Link social accounts Initializes an OAuth linking process. ```tsx auth.tsx import openfort from "./openfortConfig" const provider = 'OAuth provider'; async function initLinkOAuth() { await openfort.initLinkOAuth({provider}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Link wallets Links a wallet using SIWE. ```tsx auth.tsx import openfort from "./openfortConfig" const signature = 'SIWE signature'; const message = 'SIWE message'; const walletClientType = 'Wallet client type'; const connectorType = 'Connector type'; const authToken = 'YOUR_USER_AUTH_TOKEN'; async function linkWallet() { await openfort.linkWallet({signature, message, walletClientType, connectorType, authToken}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Link third party providers Links a third party provider to an existing account using an authentication token. ```tsx auth.tsx import openfort from "./openfortConfig" const provider = 'Third Party provider'; const token = 'Third Party token'; const tokenType = 'Type of the token (idToken or customToken)' async function linkThirdParty() { await openfort.linkThirdPartyProvider({provider, token, tokenType}); } ``` ## Unlinking accounts Once a user has linked additional accounts to their profile, you may also want to give them the option to unlink those accounts. ### Unlink email Unlinks an email and password from an existing account using an authentication token. ```tsx auth.tsx import openfort from "./openfortConfig" const email = 'EMAIL'; async function unlinkEmailPassword() { await openfort.unlinkEmailPassword(email); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Unlink social accounts Unlinks an OAuth provider from the account. ```tsx auth.tsx import openfort from "./openfortConfig" const provider = 'OAuth provider'; async function unLinkOAuth() { await openfort.unLinkOAuth({provider}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Unlink wallets Unlinks a wallet. ```tsx auth.tsx import openfort from "./openfortConfig" const address = 'Wallet address'; const authToken = 'YOUR_USER_AUTH_TOKEN'; async function unlinkWallet() { await openfort.unlinkWallet({provider, address}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ### Unlink third party provider Unlinks a third party provider from an existing account using an authentication token. ```tsx auth.tsx import openfort from "./openfortConfig" const provider = 'Third Party provider'; const token = 'Third Party token'; const tokenType = 'Type of the token (idToken or customToken)' async function unlinkThirdParty() { await openfort.unlinkThirdPartyProvider({provider, token, tokenType}); } } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/external-auth.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Third-party auth providers', description: 'Integrate with existing auth providers and backends', subtitle: 'Learn how to integrate with third-party auth provider.', breadcrumb: 'Authentication', } Openfort's embedded signers are fully-compatible with any authentication provider that supports JWT-based, stateless authentication. If you're looking to add embedded signers to your app, you can either: You will need to call the `authenticateWithThirdPartyProvider` method: ```tsx import {ThirdPartyOAuthProvider, TokenType} from "@openfort/openfort-js"; await openfort.authenticateWithThirdPartyProvider({ provider: ThirdPartyOAuthProvider.FIREBASE, // or SUPABASE, etc. token: "YOUR_USER_AUTH_TOKEN", tokenType: TokenType.ID_TOKEN, // or CUSTOM_TOKEN }); ``` To make these instructions concrete, this guide uses [Firebase](https://firebase.com) as a sample third party auth provider that you can integrate alongside Openfort. Follow the guide on how to [configure third party auth](/docs/guides/dashboard/external-auth) to learn more. The supported loginMethods are `'accelbyte'`, `'custom'`, `'firebase'`, `'supabase'`, `'lootlocker'`, `'playfab'`, `'telegramMiniApp'` and `'oidc'`. ```tsx auth.tsx import {GoogleAuthProvider, getAuth, signInWithPopup} from "firebase/auth"; import {ThirdPartyOAuthProvider, TokenType} from "@openfort/openfort-js"; import openfort from "./openfortConfig" async function loginWithGoogle() { const googleProvider = new GoogleAuthProvider(); signInWithPopup(auth, googleProvider) .then(async (result) => { const idToken = await result.user.getIdToken(); const token = await openfort.authenticateWithThirdPartyProvider({provider:ThirdPartyOAuthProvider.FIREBASE, token:idToken, tokenType:TokenType.ID_TOKEN}); }) } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` Uppon successful authentication, the SDK will return: ```json response.json { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "firebase", "disabled": false, "externalUserId": "2" } ] } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/external-wallet.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'External Wallet Login', description: 'Authenticate users with external wallets', subtitle: 'Learn how to connect the external wallets to authenticate users.', breadcrumb: 'Authentication', } Connect wallet via the [Sign in With Ethereum (SIWE)](https://eips.ethereum.org/EIPS/eip-4361) standard. Catered to users who prefer to authenticate using their external wallets, supporting various types such as injected, browser-based, and mobile wallets. Openfort’s integration facilitates a secure and direct authentication process using these wallets. First create a challenge for the user to sign with their wallet by constructing a SIWE challenge using the nonce returned from the server: ```tsx auth.tsx import openfort from "./openfortConfig" const address = 'EXTERNAL_WALLET_ADDRESS'; async function initSIWE() { await openfort.initSIWE({address}); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` Then, verify the SIWE signature to authenticate the user: - `walletClientType`: e.g. coinbaseWallet, metamask, etc. - `connectorType`: wallet_connect_v2, injected, coinbase_wallet, etc. ```jsx import openfort from "./openfortConfig" const address = 'EXTERNAL_WALLET_ADDRESS'; async function authSIWE(signature, message, walletClientType, connectorType) { await openfort.authenticateWithSIWE({ signature: signature, message: SIWEMessage, connectorType: connector?.type, walletClientType: connector?.name, }); } ``` And you’re done! The user is now authenticated and can access your application. Uppon successful authentication, the SDK will return a token that can be used to authenticate the user in your application. ```json response.json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "wallet", "address": "0x1234567890abcdef", "disabled": false, } ] }, "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJhdWQiOiJwcm9fOGY3ZTM1NTktMjhkNy00MWE2LTgxNGMtMjU0OTkzZTdkNjFkLXRlc3QiLCJleHAiOjE3MTA5ODI2MDIsImlhdCI6MTcxMDk3OTAwMiwiaXNzIjoib3BlbmZvcnQueHl6Iiwic2lkIjoiMzhhMDdmMzktMTUxOS00MjE0LWJmNmMtNzI0Zjg0ZDBiZGQwIiwic3ViIjoicGxhX2NjOWVkMmI3LWM1ZjUtNGM0My04ZGNhLWM0YjEwNGJhMTc2MiJ9.EcFtS__GwyxJu1S3tO7jMBbTCIJCpqsoNxxJrqILrKjNl2N5-SIMG2z_s2Vs8ztG6KAVy6zIp6P9GzfD7s4JiA", "refreshToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJzaWQiOiIzOGEwN2YzOS0xNTE5LTQyMTQtYmY2Yy03MjRmODRkMGJkZDAiLCJpYXQiOjE3MTA5NzkwMDIsImV4cCI6MTcxMzU3MTAwMn0.koNd4eoevBQQR3-z0CMGL5qVzOURZEeAgjvrHMRloLgDbScS2Qbi4W-vf2fE0fYOWUIAHnAq7cDABNwSQrEvSQ" } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/guest.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Guest Mode', description: 'Enable users to quickly start using your application without registration', subtitle: 'Learn how to implement guest authentication in your application', breadcrumb: 'Authentication', } Guest accounts allow users to immediately start using your application without going through a full registration process. This feature is particularly useful for applications where you want to reduce friction in the user onboarding process. ### Key Features - They are locally persisted, so guest users can leave and return to the same account on the same device. - Locally persisted sessions. - Fully functional embedded wallets. - Upgradeable to fully logged-in accounts. - They can be logged out and deleted as needed. User data and embedded wallets from guest sessions cannot be merged into an existing user account — guest accounts can only be upgraded into a new user account. If a guest user wants to log in with an existing account, you must delete the guest user session first. ## Implementation ### Create a guest account (client-side) Use the `signUpGuest` method from the Openfort SDK to create a guest account: ```tsx auth.tsx import openfort from "./openfortConfig"; async function handleGuest() { try { const data = await openfort.signUpGuest(); // Handle successful guest registration // The response includes player information and authentication tokens } catch (error) { // Handle error } } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` Upon successful registration, you'll receive a response containing the player information and authentication tokens: ```json { "player": { "id": "pla_...", "object": "player", "createdAt": 1234567890, "linkedAccounts": [] }, "token": "eyJhbG...", "refreshToken": "eyJhbG..." } ``` - Display guest access alongside normal login options - Use clear labeling to distinguish between guest and full account creation ```javascript const LoginOptions = () => { return (
); }; ```
### Upgrade a guest user to a logged-in user Simply call [link method](/docs/guides/auth/user-management/linking) to enable the guest user to upgrade their account to a logged-in account using any authentication method of their choice. ## Example Implementation Here's a complete example of a guest authentication flow: ```javascript import openfort from "./openfortConfig"; import { useRouter } from "next/router"; import { useState } from "react"; function GuestAuth() { const router = useRouter(); const [status, setStatus] = useState(null); const handleGuest = async () => { setStatus({ type: "loading", title: "Creating guest account...", }); try { const data = await openfort.signUpGuest(); setStatus({ type: "success", title: "Guest account created", }); // Store credentials and redirect openfort.storeCredentials({ player: data.player.id, accessToken: data.token, refreshToken: data.refreshToken, }); router.push("/"); } catch (error) { setStatus({ type: "error", title: "Error creating guest account", }); } }; return (
); } ```
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/oauth-login.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Social Login (OAuth)', breadcrumb: 'Authentication', } To initiate sign in, you can use the `initOAuth()` method from the Openfort JavaScript library and provide a `redirectTo` URL which points to a callback route. - **Implicit flow**: that's all you need to do. The user will be taken to Google's consent screen, and finally redirected to your app with an access and refresh token pair representing their session. - **Pooling flow**: for example in Server-Side Auth, you need to redirect the user back to your website. You will need to call the `initOAuth` method: ```tsx import {OAuthProvider} from "@openfort/openfort-js"; await openfort.initOAuth({ provider: OAuthProvider.GOOGLE, // or FACEBOOK, TWITTER, etc. options: { // Depdening on the flow // redirectTo: 'https://your-website.com/login', // usePooling: true, }, }); ``` Configure your social login providers at [your dashboard](https://dashboard.openfort.xyz/players/auth/providers). Follow the guide on how to [configure social login](/docs/guides/dashboard/social-login) to learn more. Configure your social login providers from your dashboard. Follow the guide on how to [configure social login](/docs/guides/dashboard/social-login) to learn more. The supported loginMethods are `'google'`, `'twitter'`, `'discord'`, `'facebook'`, `'telegram'`, `'line'` or `'epic_games'`. ```tsx auth.tsx import { OAuthProvider } from '@openfort/openfort-js'; import openfort from "./openfortConfig" function AuthButton() { return ( ); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` ```json response.json { "url": "redirect-url", "key": "key" } ``` Now you can redirect the user to the initOAuth.url and when the process is done, you will be redirected to the redirectTo url with tokens `https://your-website.com?access_token=...&refresh_token=...&player_id=...` You can then use those parameters to authenticate the user: ```ts openfort.storeCredentials({ player: player_id, accessToken: access_token, refreshToken: refresh_token, }); ``` You can pool the auth with the key returned from the initOAuth, this will check if the auth is ready every 0.5 seconds for 5 minutes sessions live for 1 hour, so you can pool the auth again if you need to. ```tsx auth.tsx import { OAuthProvider } from '@openfort/openfort-js'; import openfort from "./openfortConfig" function AuthButton() { return ( ); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` Uppon successful authentication, the SDK will return a token that can be used to authenticate the user in your application. ```json response.json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "facebook", "disabled": false, "externalUserId": "2" } ] }, "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJhdWQiOiJwcm9fOGY3ZTM1NTktMjhkNy00MWE2LTgxNGMtMjU0OTkzZTdkNjFkLXRlc3QiLCJleHAiOjE3MTA5ODI2MDIsImlhdCI6MTcxMDk3OTAwMiwiaXNzIjoib3BlbmZvcnQueHl6Iiwic2lkIjoiMzhhMDdmMzktMTUxOS00MjE0LWJmNmMtNzI0Zjg0ZDBiZGQwIiwic3ViIjoicGxhX2NjOWVkMmI3LWM1ZjUtNGM0My04ZGNhLWM0YjEwNGJhMTc2MiJ9.EcFtS__GwyxJu1S3tO7jMBbTCIJCpqsoNxxJrqILrKjNl2N5-SIMG2z_s2Vs8ztG6KAVy6zIp6P9GzfD7s4JiA", "refreshToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJzaWQiOiIzOGEwN2YzOS0xNTE5LTQyMTQtYmY2Yy03MjRmODRkMGJkZDAiLCJpYXQiOjE3MTA5NzkwMDIsImV4cCI6MTcxMzU3MTAwMn0.koNd4eoevBQQR3-z0CMGL5qVzOURZEeAgjvrHMRloLgDbScS2Qbi4W-vf2fE0fYOWUIAHnAq7cDABNwSQrEvSQ" } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/password.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Email and Password', description: 'Allow users to sign in with a password connected to their email ', breadcrumb: 'Authentication', } Users often expect to sign in to your site with a password. Openfort Auth helps you implement password-based auth safely, using secure configuration options and best practices for storing and verifying passwords. {/* Set up password for your Openfort project. - Enable the email provider in your [Openfort Project](/dashboard/project/_/auth/providers) - Configure the Site URL and any additional redirect URLs in the [authentication management tab](/dashboard/project/_/auth/url-configuration). - The Site URL represents the default URL that the user will be redirected to after clicking on the email signup confirmation link. */} You can update the server sending email notifications and the email templates through your dashboard. Visit the guide on how to [update password authentication](/docs/guides/dashboard/password/custom-smtp) to learn more. ## Sign up a user You directly receives the access token after the user confirms their email. To sign up the user, call signUpWithEmailPassword() with their email address and password. You can optionally specify a URL to redirect to after the user clicks the confirmation link. This URL must be configured as a Redirect URL. If you don't specify a redirect URL, the user is automatically redirected to your site URL. ```tsx auth.tsx import openfort from "./openfortConfig" async function signUpNewUser(email:string, password:string, firstName:string, lastName:string) { await openfort.signUpWithEmailPassword({ email: email, password: password, options: { data: { name: firstName + ' ' + lastName, }, }, }); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", } }); export default openfort; ``` If you want the users to verify their email, you can send them an email after sign up with: ```ts await openfort.requestEmailVerification({ email: email, redirectUrl: 'http://example.com/account/register', }); ``` ## Log in a user When your user signs in, call logInWithEmailPassword() with their email address and password: ```ts import Openfort from "@openfort/openfort-js"; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY" } }); async function logInpUser() { await openfort.logInWithEmailPassword({ email: email, password: password }); } ``` Uppon successful authentication, the SDK will return a token that can be used to authenticate the user in your application. ```json response.json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "email", "disabled": false, "verified": true, "email": "hello@example.com" } ] }, "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJhdWQiOiJwcm9fOGY3ZTM1NTktMjhkNy00MWE2LTgxNGMtMjU0OTkzZTdkNjFkLXRlc3QiLCJleHAiOjE3MTA5ODI2MDIsImlhdCI6MTcxMDk3OTAwMiwiaXNzIjoib3BlbmZvcnQueHl6Iiwic2lkIjoiMzhhMDdmMzktMTUxOS00MjE0LWJmNmMtNzI0Zjg0ZDBiZGQwIiwic3ViIjoicGxhX2NjOWVkMmI3LWM1ZjUtNGM0My04ZGNhLWM0YjEwNGJhMTc2MiJ9.EcFtS__GwyxJu1S3tO7jMBbTCIJCpqsoNxxJrqILrKjNl2N5-SIMG2z_s2Vs8ztG6KAVy6zIp6P9GzfD7s4JiA", "refreshToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJzaWQiOiIzOGEwN2YzOS0xNTE5LTQyMTQtYmY2Yy03MjRmODRkMGJkZDAiLCJpYXQiOjE3MTA5NzkwMDIsImV4cCI6MTcxMzU3MTAwMn0.koNd4eoevBQQR3-z0CMGL5qVzOURZEeAgjvrHMRloLgDbScS2Qbi4W-vf2fE0fYOWUIAHnAq7cDABNwSQrEvSQ" } ``` ## Resetting a password (Forgot password) ### Step 1: Create a reset password page Create a reset password page. This page should be publicly accessible. Collect the user's email address and request a password reset email. Specify the redirect URL, which should point to the URL of a change password page. ```ts await openfort.requestResetPassword({ email: 'hello@example.com', redirectUrl: 'http://example.com/account/update-password', }) ``` ### Step 2: Create a change password page Create a change password page at the URL you specified in the previous step. This page should be accessible only to authenticated users. Collect the user's new password and call updateUser to update their password. You should also pass the state parameters, which should be available in the URL of the change password page. This is to prevent CSRF attacks. ```ts await openfort.resetPassword({ email: 'hello@example.com', password: 'new-password', state: 'verification-state', }) ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/user-management.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'User Management', description: 'Using Openfort Auth to manage users.', subtitle: 'Manage your users with Openfort Auth', breadcrumb: 'Authentication', } ## The user object Use the Auth Players page of the dashboard to manage all of your app's users and their linked accounts. Every authenticated user with Openfort Auth results in a JSON that combines the user's information with the Openfort player `id`: ```json { "id": "pla_ff54b031-a878-4ca2-9cf5-ae190f921e9b", "object": "player", "createdAt": 1691658234, "linkedAccounts": [ { "provider": "email", "email": "jaume@openfort.xyz", "disabled": false, "updatedAt": 1691658234 } ] } ``` After a player has authenticated, an Openfort player `id` is created for them and is accessible through your Openfort Dashboard.
authenticated players
## Deleting users From the user drawer, you can delete a user if necessary. This is an irreversible and destructive action although the associated player will not be deleted; if the user logs into your app again, they will have a new player id, will have to relink any formerly linked accounts, and will get a new embedded signer address. Please take extreme care when deleting users. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth/user-sessions.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'User Session (JWT/Authorization)', description: 'Using Openfort Auth to onboard new users.', subtitle: 'Understand how to onboard with the Openfort signer solution.', breadcrumb: 'Authentication', } ## What is a session? A session is created when a user signs in. By default, it lasts 1 hour and a user can have an unlimited number of active sessions. A session is represented by the Openfort Auth access token in the form of a JWT, and a refresh token which is a unique string. Access tokens are designed to be short lived while refresh tokens never expire but can only be used once. You can exchange a refresh token only once to get a new access and refresh token pair. This process is called **refreshing the session.** A session terminates, depending on configuration, when: - The user clicks sign out. - The user changes their password or performs a security sensitive action. - It times out due to inactivity. - It reaches its maximum lifetime. - A user signs in on another device. ### Access token format Openfort access tokens are JSON Web Tokens (JWT), signed with the ES256 algorithm. These JWTs include certain information about the user in its claims, namely: - `sid` is the user’s current session ID - `sub` is the user’s player Id - `iss` is the token issuer, which should always be openfort.xyz - `aud` is your Openfort app ID - `iat` is the timestamp of when the JWT was issued - `exp` is the timestamp of when the JWT will expire and is no longer valid. This is generally 1 hour after the JWT was issued. ## Authorizing requests with the access token To include the current user's access token on requests to your backend, follow the instructions below. Make sure to follow the appropriate instructions if your app uses local storage. ```ts const authToken = openfort.getAccessToken(); const response = await fetch(, { method: body: , headers: { 'Authorization': `Bearer ${accessToken}`, /* Add any other request headers you'd like */ } }); ``` Visit our guide to [verify tokens server-side](/docs/guides/server/access-token) to learn how to validate the access token on your backend. ## Log out a user When your user logs out, call `logout()` to remove them from the browser session and any objects from localStorage. ```js import Openfort from "@openfort/openfort-js"; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY" } }); async function logout() { await openfort.logout(); } ``` Upon sign out, all refresh tokens and potentially other database objects related to the affected sessions are destroyed and the client library removes the session stored in the browser. Access tokens of revoked sessions remain valid until their expiry time, encoded in the `exp` claim. The user won't be immediately logged out and will only be logged out when the access token expires. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/advanced/iframe.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'iframe Service', breadcrumb: 'Wallets', description: 'Use Openfort embedded signer to seamlessly create non-custodial smart accounts for your players.', } The iframe service is a crucial element in ensuring the security and privacy of a user's private keys. The isolated iframe operates as a secure environment, managing the private key and executing wallet operations. This setup is pivotal because it keeps the private key confined to an in-memory state within the iframe, never storing it in a database or allowing it to persist beyond the session. This isolation also means the private key is protected from potential exposure or theft, as it's inaccessible to both the app's code and the Openfort SDK. Self hosting and writing your own iframe communication code is a complex task. We recommend using the [@openfort/openfort-js](https://www.npmjs.com/package/@openfort/openfort-js) to interact with the iframe. The SDK provides a simple and secure way to communicate with the iframe service. This guide provides a step-by-step approach to downloading and running the openfort/iframe Docker image, which is hosted on Docker Hub. By following these instructions, you will be able to set up and host the image on your local machine or server environment. ## Hosting the iframe ### Prerequisites Before you begin, make sure you have the following installed: - Docker: Ensure you have Docker installed on your machine. If not, download and install Docker from the [official website](https://docs.docker.com/engine/install/). ### Step 1: Pulling the Docker Image To start, you'll need to pull the openfort/iframe image from Docker Hub. Open a terminal and run the following command: ```bash docker pull openfort/iframe ``` or use the following command to pull the image from the Docker Hub:
{image.map((x) => (
{x.description}
))}
export const image = [ { name: 'iframe docker image', description: 'Self-hostable iframe service for key generation and signing transactions.', href: 'https://hub.docker.com/r/openfort/iframe', } ] This command downloads the latest version of the openfort/iframe image to your local machine. If you need a specific version, you can tag it like this: openfort/iframe:tagname. ### Step 2: Running the Docker Image Once the image is pulled, you can run it as a container. To do this, execute the following command in your terminal: ```bash docker run -d -p 8080:80 openfort/iframe ``` Here, -d runs the container in detached mode (in the background), and -p 8080:80 maps port 80 of the container to port 8080 on your host machine. Adjust the port settings as needed for your environment. ### Step 3: Accessing the Application After the container starts, you can access the application by opening a web browser and navigating to http://localhost:8080. You should see the Openfort iframe service running and ready for use. ## Interacting with the iframe The iframe service provides a set of APIs that allow you to interact with the embedded signer. These APIs enable you to create, sign, and broadcast transactions, as well as manage accounts and keys. ### Communicating with the iframe We have created a client side library to help you interact with the iframe service. You can find the library on:
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'iframe client SDK', description: 'A client library to communicate with the Openfort iframe service.', href: 'https://github.com/openfort-xyz/iframe-client', } ] export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/advanced/shield.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Shield (automatic recovery)', breadcrumb: 'Wallets', description: 'Use Openfort embedded signer to seamlessly create non-custodial smart accounts for your players.', } This guide is for developers that want to self-host Shield (automatic recovery) for their users. If you are a user looking to use Shield and to understand how it works, please refer to the [user guide](/docs/guides/javascript/embedded-signer/recovery). In automatic recovery, Openfort uses Shield to encrypt and store the **recovery share** of the embedded signer on behalf of the user. In the case you do not require a passcode from your users, you are trusting whoever hosts Shield's infrastructure as well as setting the user's authentication token as the sole root of trust for their wallet. We generally recommend you prompt users to set a recovery passcode upfront, especially as assets in a wallet grow.
{image.map((x) => (
{x.description}
))}
export const image = [ { name: 'Shield', description: 'Self-hostable Shield service.', href: 'https://github.com/openfort-xyz/shield', } ] ### Communicating with Shield We have created a client side library to help you interact with the Shield service. You can find the library on:
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'Shield client SDK', description: 'A client library to communicate with the Openfort Shield service.', href: 'https://github.com/openfort-xyz/shield-js', } ] export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/advanced.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Advanced (self-hosted)', description: 'Self-hosting, advanced configuration, and more.', breadcrumb: 'Embedded signer', } These are **low-level** guides for developers who want to customize the signer experience. If you're looking for a quick way to get started, check out the [quick start guide](/docs/guides/javascript/embedded-signer/recovery). Openfort's embedded signer is designed for complete customization and control. This guide will walk you through the advanced features and configurations available to you.
advanced-embedded-signer
## Self-hosting
{'Learn how reconstruct and create an embedded Signer. Deploy your own iframe and interact with it.'} {'Learn how host your own automatic recovery server.'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/export-key.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Exporting the embedded signer', description: 'Learn how to export the private key', breadcrumb: 'Embedded signer', } This allows them to use their embedded signer address with another wallet client, such as Metamask in any application. Note that this embedded signer is only controlling the smart account and does not hold assets in it. If you want to simply transfer ownership to a Metamask and interact with a smart contract, we'll recommend checking the [transfer ownership section](/docs/guides/javascript/smart-wallet/advanced/transfer-ownership). To have your user export their embedded signer's private key, use the `exportPrivateKey` method from the SDK. If your user is not `authenticated` or has not yet created an embedded signer in your game, this method will fail. As an example, you might attach `exportPrivateKey` as an event handler to an export signer button in your app: ```tsx ExportWalletButton.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` function ExportWalletButton() { const handleExportWalletButton = async () => { const privateKey = await openfort.exportPrivateKey(); console.log(privateKey); }; return ( ); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` When your user exports their embedded signer, their private key is assembled on a different origin than your app's origin. This means neither you nor Openfort can ever access your user's private key. **Your user is the only party that can ever access their full private key.** export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/recovery.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Create and recover signers', description: 'Create and manage embedded wallets for your users', subtitle: 'Create and manage embedded wallets for your users', breadcrumb: 'Embedded signer', } ## Creating embedded signers To create wallets for your users as part of the login flow you need to set the `configureEmbeddedSigner`. The configure parameter depends on the type of recovery you want to enable in your app. Therefore, it's important to first decide the recovery method of the signer. **Make sure to wait for the embedded state ready before using the embedded signer. Learn more about [how to check the embedded state](/docs/guides/javascript/use-openfort#waiting-for-ready).** ## Decide a recovery method Recovering the embedded signer is needed when a user logs into a new device or when the embedded signer is lost. Openfort embedded signers have two core recovery modes: automatic recovery and user-based recovery. At a high-level, this setting modulates how the embedded signer's recovery share is encrypted and stored. - **[Automatic recovery](/docs/guides/javascript/embedded-signer/recovery#automatic-recovery)**: The recovery share is encrypted with a combination of project entropy and Openfort's entropy. When logging into a new device, users can immediately access their embedded signer. Before configuring the automatic recovery, generate your project's **publishable and secret shield keys** and store the **encryption share**. Learn about the differrent API keys [here](/docs/api-keys#shield-secret-and-publishable-keys). - **[User-based recovery](/docs/guides/javascript/embedded-signer/recovery#user-based-recovery):** The recovery share is encrypted by **user-provided entropy**. When logging into a new device, users must enter in their password to recover the embedded signer on the new device. Once the embedded signer has been recovered on a device, users will not need to enter their password on that devices again. Refer to [social recovery](/docs/guides/javascript/smart-wallet/advanced/social-recovery) to make your accounts less dependent on offchain recovery methods. ### Automatic recovery It is worth noting that while **automatic recovery** makes for smooth user UX (without needing to set up a recovery system upfront when logging in), it comes with tradeoffs. Notably, the root of trust with is in the user’s authentication token. This means access to the auth token grants access to the wallet. Accordingly, this token must be properly secured at all times. When using automatic recovery, **Shield** generates a password that is used for the encryption of the recovery share. The full encryption key can only be accessed if the decryption request includes the user's auth token. When using **automatic recovery**, its very important to ensure that the `encryption share` should not be available from the client side of the application. **From your backend**, you should have an endpoint that generates an encryption session for the user. This endpoint should be protected and only accessible by the user who is requesting the encryption session (i.e. the user who is logging in). An encryption session is requested every time `configureEmbeddedSigner` is called. The encryption session is only valid for **a single use**. For example, in a Next.js API route, you can create an endpoint like this: ```ts protected-create-encryption-session.ts import openfort from './openfortAdminConfig'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const session = await openfort.registerRecoverySession('YOUR_SHIELD_PUBLISHABLE_KEY', 'YOUR_SHIELD_SECRET_KEY', 'YOUR_SHIELD_ENCRYPTION_SHARE') res.status(200).send({ session: session, }); } ``` ```ts openfortAdminConfig.ts import Openfort from '@openfort/openfort-node'; const openfort = new Openfort('YOUR_OPENFORT_SECRET_KEY'); export default openfort; ``` Once we've secured the backend we setup the client side: ```tsx configure.tsx import {ShieldAuthType, ShieldAuthentication} from '@openfort/openfort-js'; import openfort from "./openfortConfig" import getEncryptionSession from "./encryptionSession" async function authSetAutomaticRecoveryMethod(email:string, password:string) { const response = await openfort.signUpWithEmailPassword({email, password}); const chainId = 80002; const shieldAuth: ShieldAuthentication = { auth: ShieldAuthType.OPENFORT, token: response.token, encryptionSession: await getEncryptionSession() }; await openfort.configureEmbeddedSigner(chainId, shieldAuth); } ``` ```ts encryptionSession.ts const getEncryptionSession = async (): Promise => { try { const response = await fetch('https://your-api-endpoint.com/api/protected-create-encryption-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); const data = await response.json(); return data.session; } catch (error) { throw new Error('Failed to create encryption session'); } }; export default getEncryptionSession; ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` This example will showcase **Firebase** as the third-party auth provider. You can replace it with any other [third-party auth provider](/docs/guides/javascript/auth/external-auth). ```tsx configure.tsx import {ShieldAuthType, ShieldAuthentication, ThirdPartyOAuthProvider, TokenType} from '@openfort/openfort-js'; import openfort from "./openfortConfig" import getEncryptionSession from "./encryptionSession" async function authSetAutomaticRecoveryMethod(idToken: string) { await openfort.authenticateWithThirdPartyProvider({provider: ThirdPartyOAuthProvider.FIREBASE, token: idToken, tokenType: TokenType.idToken}); const chainId = 80002; const shieldAuth = { auth: ShieldAuthType.OPENFORT, token: idToken, authProvider: "firebase", tokenType: "idToken", encryptionSession: await getEncryptionSession() }; await openfort.configureEmbeddedSigner(chainId, shieldAuth); } ``` ```ts encryptionSession.ts const getEncryptionSession = async (): Promise => { try { const response = await fetch('https://your-api-endpoint.com/api/protected-create-encryption-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); const data = await response.json(); return data.session; } catch (error) { throw new Error('Failed to create encryption session'); } }; export default getEncryptionSession; ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` We recommend enabling user-based recovery for users. This is especially important to enforce as the value of assets in a user's wallet grows. --- ### User-based recovery **Password recovery** Require that users set a password when the wallet is created, enforcing password-based recovery from the start. If encrypted by user-provided entropy, **only the user can decrypt the recovery share**. Openfort never sees or the user's password. Therefore, if you're not planning to ever user the automatic recovery mode, you can use the `encryption share` in the client side of the application. ```tsx configure.tsx import {ShieldAuthType, ShieldAuthentication} from '@openfort/openfort-js'; import openfort from "./openfortConfig" async function authSetPasswordRecoveryMethod(email:string, password:string, recoveryPassword:string) { const response = await openfort.signUpWithEmailPassword({email, password}); const chainId = 80002; const shieldAuth: ShieldAuthentication = { auth: ShieldAuthType.OPENFORT, token: response.token }; await openfort.configureEmbeddedSigner(chainId, shieldAuth, recoveryPassword); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", shieldEncryptionKey: "YOUR_SHIELD_ENCRYPTION_SHARE", }, }); export default openfort; ``` This example will showcase **Firebase** as the third-party auth provider. You can replace it with any other third-party auth provider [supported by Openfort](/docs/guides/javascript/auth/external-auth) or with [Custom Auth](/docs/guides/javascript/auth/custom-auth). ```tsx configure.tsx import {ShieldAuthType, ShieldAuthentication, ThirdPartyOAuthProvider, TokenType} from '@openfort/openfort-js'; import openfort from "./openfortConfig" async function authAndSetPassordRecoveryMethod(idToken: string, password: string) { await openfort.authenticateWithThirdPartyProvider({provider:ThirdPartyOAuthProvider.FIREBASE, token: idToken, tokenType: TokenType.idToken}); const chainId = 80002; const shieldAuth: ShieldAuthentication = { auth: ShieldAuthType.OPENFORT, token: idToken, authProvider: "firebase", tokenType: "idToken", }; await openfort.configureEmbeddedSigner(chainId, shieldAuth, password); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", shieldEncryptionKey: "YOUR_SHIELD_ENCRYPTION_SHARE", }, }); export default openfort; ``` --- ## Pregeneration Openfort also allows you to pregenerate embedded wallets for your users, even before they first login to your app. Please see our [pregeneration guide](/docs/guides/server/pregenerate-wallets) for more. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/sign-messages.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Sign messages with the embedded signer ', breadcrumb: 'Embedded signer', } To request personal signatures from your embedded signer, you can either: - use the wallet's EIP-1193 provider to send JSON-RPC requests to the wallet directly. - pass the wallet to a library like `viem`, `ethers`, or `wagmi`. - for the embedded signer specifically, use Openfort's native `signMessage` and `sendTypedMessage` methods. The guide below explains how to request signatures and transactions via the **Openfort native methods**. ## Signing messages To request a signature from a user, use the `signMessage` method. When invoked, `signMessage` will request an EIP-191 [personal_sign](https://docs.metamask.io/wallet/reference/personal_sign/) signature from the embedded signer, and returns a Promise for the user's signature as a string. ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` async function signMessageButton(message:string) { await openfort.signMessage(message); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` ## Signing typed data To have a user sign an EIP-712 typed data signature, use the `signTypedData` method. When invoked, `signTypedData` will request an EIP-721 [eth_signTypedData_v4](https://docs.metamask.io/wallet/reference/eth_signtypeddata_v4/) signature from the embedded signer, and returns a Promise for the user's signature as a string. ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` async function signTypedMessageButton(domain: any, types: any, value: any) { await openfort.signTypedData(domain, types, value); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/embedded-signer/update-recovery.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Update recovery method', description: 'Switch between different recovery methods', subtitle: 'Switch between different recovery methods', breadcrumb: 'Embedded signer', } Once a wallet has been created, users have the ability to upgrade from automatic recovery to a user-owned recovery method, or to switch between different user-owned recovery methods. ## Upgrading a user's recovery method To update the recovery method, you will need to call the `setEmbeddedRecovery`: ```tsx await openfort.setEmbeddedRecovery({ recoveryMethod, recoveryPassword, encryptionSession, }); ``` In order to update the recovery method, you will need to request the user for their **password**. Users can **reset their password** using this method as well. When calling `setEmbeddedRecovery`, then recovery method will be updated to the new method provided. The user won't be required to reconstruct their embedded signer right after. As an example, you might add `setEmbeddedRecovery` as an event handler for a set recovery button in your app: ```tsx UpdateRecoveryButton.tsx import openfort from './openfortConfig'; import {RecoveryMethod} from '@openfort/openfort-js'; import getEncryptionSession from "./encryptionSession" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` function AddOrUpdateRecoveryButton() { const handleUpdateRecovery = async () => { const password = ( document.querySelector( `input[name="password"]` ) as HTMLInputElement ).value; const recoveryMethod = RecoveryMethod.PASSWORD; const recoveryPassword = password; const encryptionSession = await getEncryptionSession(); await setWalletRecovery({ recoveryMethod, recoveryPassword, encryptionSession, }); }; return (
); } ``` ```ts encryptionSession.ts const getEncryptionSession = async (): Promise => { try { const response = await fetch('https://your-api-endpoint.com/api/protected-create-encryption-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); const data = await response.json(); return data.session; } catch (error) { throw new Error('Failed to create encryption session'); } }; export default getEncryptionSession; ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ```
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/resources/telegram-react.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Telegram-react', title: 'Integrate React app on Telegram mini-app', description: 'Learn how you can integrate React app on Telegram mini-app', subtitle: 'Integrate React app on Telegram mini-app', } ## Overview Building a new app? Check out the [Sample Telegram](https://github.com/openfort-xyz/sample-telegram/), which includes a basic Telegram <> Openfort integration. ## Prerequisites We will be using the Openfort SDK to integrate the React app on Telegram mini-app. If you haven't set up the Openfort SDK in your project, follow the [quickstart guide](/docs/guides/unity/quickstart). ## Configuration ### Telegram mini-app setup + Create a Telegram bot and get the bot token. Follow the [official guide](https://core.telegram.org/bots#6-botfather) to create a bot and get the token. + [Configure your project providers](https://dashboard.openfort.xyz/players/auth/providers) Enable the Telegram provider and add the bot username and bot token.
Contract Info
Enable the Telegram (Mini-app) provider and add the bot token.
Contract Info
## Frontend setup + In your frontend project, we will authenticate the user with the Telegram provider. ```ts await openfort.authenticateWithThirdPartyProvider({ provider: ThirdPartyOAuthProvider.TELEGRAM_MINI_APP, token: initDataRaw, tokenType: TokenType.CUSTOM_TOKEN }); ``` The `token` is the `initDataRaw` you receive from the Telegram SDK after initializing the Telegram mini-app. In react, you would use `@telegram-apps/sdk-react` to retrieve the `initDataRaw`: ```tsx import openfort from "../utils/openfortConfig.ts"; import { ThirdPartyOAuthProvider, TokenType } from "@openfort/openfort-js"; import { retrieveLaunchParams } from "@telegram-apps/sdk-react"; const SampleComponent = () => { const { initDataRaw } = retrieveLaunchParams(); useEffect(() => { if (initDataRaw) { openfort.authenticateWithThirdPartyProvider({ provider: ThirdPartyOAuthProvider.TELEGRAM_MINI_APP, token: initDataRaw, tokenType: TokenType.CUSTOM_TOKEN }).then(() => { console.log("Authenticated!"); }).catch((error) => { console.error("Failed to authenticate:", error); }) } }, [initDataRaw]); // ... other code } ``` For more information on how to integrate the Telegram mini-app SDK, refer to the [official documentation](https://core.telegram.org/widgets/login). More information about external authentication can be found in the [external auth guide](/docs/guides/javascript/auth/external-auth). export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/advanced/session-keys.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'session-keys', title: 'Using session keys', description: 'How to create and manage session keys', subtitle: 'How to create and manage session keys', tocVideo: 'rh2E02PATlU', breadcrumb: 'Smart wallets', } Session keys are programmable access tokens with specific permissions, designed for controlled interactions. Examples include: - Granting access to specific areas or features. - Limiting usage to a set amount of resources (e.g., 1000 units of currency). - Time-bound validity (e.g., expiring after 3 days). P ermissions can be combined, enabling fine-tuned, context-specific capabilities. Session Keys streamline interactions by: - Seamless Interactions: Reducing the need for repeated confirmations by delegating specific permissions to locally stored keys, enhancing user experience. - Automated Processes: Enabling automation through server-bound keys with defined permissions for tasks like recurring actions, resource management, or condition-based triggers. Check out our sample registering a session key with an account with a non-custodial signer: [GitHub source](https://github.com/openfort-xyz/openfort-js/tree/main/examples/apps/auth-sample). ## Configuration This section will guide you through the process of registering a session key and using it to mint an asset with a player's smart account. You can choose to create the session key using a **web3 libraries** or using the **Openfort native method**. Using [EIP-7715](https://github.com/pedrouid/ERCs/blob/19c16341c57f6ac8770cb778d60845dcf30f6a40/ERCS/erc-7715.md). The `request` method of the EIP-1193 provider can be used to request signatures. First, get the provider: ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = openfort.getEthereumProvider(); ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` Smart wallets support sending a batch of transactions in a single, atomic submission to the network. To register a session key with a smart wallet, call the `wallet_grantPermissions` method. As an example, you might batch together a transaction to approve a USDC spender and to transfer USDC like so: ```tsx import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'; const sessionKey = generatePrivateKey(); const accountSession = privateKeyToAccount(sessionKey).address; await provider.request({ method: 'wallet_grantPermissions', params: [ { signer:{ type: "account", data:{ id: accountSession } }, expiry: 60 * 60 * 24, permissions: [ { type: 'contract-call', data: { address: '0x2522f4fc9af2e1954a3d13f7a5b2683a00a4543a', calls: [] }, policies: [] } ], }, ], }); ``` Popular web3 libraries provide convenient methods for registering session keys: | Library | Method | |---------|--------| | Viem | [Use the `wallet_grantPermissions` action](https://viem.sh/experimental/erc7715/grantPermissions) | For a general overview of session keys, see the [Session keys](https://www.openfort.xyz/blog/technical-dive-session-keys) post. For more information about how to use the session key endpoints, you can visit our [API documentation](/docs/reference/api/create-a-session-key). ### 1. Create a session key - Client side After you have authenticated your user with your regular authentication system, you can create a session key for them. To create a session key, you need to generate a key pair on the client-side and send the address computed from the public key to your server. Using one of the official Openfort [client libraries](/docs/libraries) everything is handled for you. 1. Install the client-side library: ```bash command-line npm install @openfort/openfort-js --save ``` 2. Initialize Openfort and create a session key: ```ts client.ts // Set your public key. Remember to switch to your live PUBLIC key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys import Openfort from '@openfort/openfort-js' const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY" } }); const sessionKey = openfort.configureSessionKey(); ``` ### 1. Create a session key - Client side Using [ethers](https://www.npmjs.com/package/ethers), you can create a key pair on the server side of you application. ```ts const sessionKey = ethers.Wallet.createRandom(); ``` The parameter `sessionKey` contains the address that you will need to register. After creating the session key, you can go ahead and register it. ### 2. Register a session key - Server side Client side To register a session key, first send the address from the session key to your server. You can get the address from the session key object created above like this: ```ts client.ts const address = sessionKey.address; ``` Then, from your server you can make a request to the Openfort API or use one of our [server libraries](/docs/libraries) to register the session key. Install Openfort in your server-side and initialize it with your secret key. ```bash command-line npm install @openfort/openfort-node ``` Initialize '@openfort/openfort-node' with your secret key. ```ts server.ts import Openfort from '@openfort/openfort-node' const openfort = new Openfort('sk_test_...'); ``` ```bash command-line dotnet add package Openfort.SDK ``` Initialize 'Openfort.SDK' with your secret key. ```csharp server.cs using Openfort.SDK; using Openfort.SDK.Model; var openfort = new OpenfortClient("sk_test_..."); ``` The created session key would be valid since the 25th of May 2023 at 7:50 GMT (timestamp `1685001000`) and last for 1 hour (timestamp `1685001000`). For a useful resource to calculate timestamps online, visit [UNIX Timestamp](https://www.unixtimestamp.com/). Note how the `externalOwnerAddress` parameter is used to indicate the address of owner of the account that will be created under the specified player. It's only necessary to specify this parameter when the player is doesn't yet have an account in that chain. Also, note how a `policy` is used to indicate the policy that will be used to sponsor the gas fees of the transaction to register the session key. In this example `externalOwnerAddress` is used to indicate the address of the owner of the account that will be created under the specified player. Register the session key using Openfort: ```bash command-line curl https://api.openfort.xyz/v1/sessions \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d validUntil=1685004600 \ -d validAfter=0 \ -d externalOwnerAddress="0x41e6...9341" \ -d policy=pol_... ``` ```ts server.ts const sessionKeyAddress = '0x76e6...9341' const policyId = 'pol_...' const playerId = 'pla_...' const validUntil = 1685001000 const validAfter = 0 const chainId = 80002 const externalOwnerAddress = '0x41e6...9341' const playerSession = await openfort.sessions.create({ player: playerId, address: sessionKeyAddress, chainId: chainId, validUntil: validUntil, validAfter: validAfter, policy: policyId, externalOwnerAddress: externalOwnerAddress, }) ``` After registering the session key, you can see it in the dashboard under the player's page.
DashboardRegisterSessionKey
### 3. Sign the session key - Client side The owner of the account of the player needs then to authorize the new session key. To do so, it needs to sign the `userOperationHash` from the `nextAction` object returned by the API call to register the session key. nextAction response object from transaction_intents ```json "nextAction": { "type": "sign_with_wallet", "payload": { "signableHash": "0x91b4efe3648c79467f7b50aa9bb1b4eae383a52dd6d741d39ece29ed2ef8362d" } }, ``` Once the content of the `nextAction` parameter above is signed by the owner signer of the account, it has to be sent to Openfort using the endpoint `/v1/sessions/:id/signature` as shown below: Sign and send the session key registration: ```bash command-line curl https://api.openfort.xyz/v1/sessions/ses_.../signature \ -H "Authorization: Bearer $YOUR_PUBLISHABLE_KEY" \ -d signature="xyz..." ``` ```ts client.ts await openfort.sendSignatureSessionRequest( playerSession.id, SIGNED_USED_OP_HASH ) ``` ### 4. Using the session key - Server side Client side After the session key is registered, it can be used to authenticate requests from the player. Whenever you create a transaction intent from your backend, a signature will be needed from the session key or owner of the players' smart account. Create a transaction intent: ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d policy=pol_... ``` ```ts server.ts const playerId = 'pla_...' const policyId = 'pol_...' const contractId = 'con_...' const chainId = 80002 const optimistic = true const interaction: Interaction = { contract: contractId, functionName: 'mint', functionArgs: [playerId], } const transactionIntent = await openfort.transactionIntents.create({ player: playerId, chainId: chainId, optimistic: optimistic, interactions: [interaction], policy: policyId, }) ``` After creating the transaction intent, the session key will need to sign the nextAction `userOperationHash` and send it to Openfort. To do so, pass the `userOperationHash` to the `sendSignatureTransactionIntentRequest` method of the Openfort client library. Load session key and sign a transaction intent: ```ts client.ts const openfortTransactionResponse = await openfort.sendSignatureTransactionIntentRequest( collectResponseJSON.data.id, userOperationHash ) ``` ### 5. Revoke a session key - Client side Server side The owner of the account can always revoke the session key. To do so, it needs to sign the `userOperationHash` from the `nextAction` object returned by the API call to revoke the session key. Create a transaction intent: ```bash command-line curl https://api.openfort.xyz/v1/sessions/revoke \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d policy=pol_... ``` ```ts server.ts const playerId = 'pla_...' const policyId = 'pol_...' const chainId = 80002 const sessionKeyAddress = '0x76e6...9341' const revokeSession = await openfort.sessions.revoke({ player: playerId, address: sessionKeyAddress, chainId: chainId, optimistic: true, policy: policyId, }) ``` Sign the transaction to revoke the session key and remove from client side: ```ts client.ts const openfortTransactionResponse = await openfort.sendSignatureTransactionIntentRequest( revokeResponseJSON.data.id, userOperationHash ); ```
{/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/advanced/sign-custodial.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'smart', title: 'Sign messages with custodial wallets', breadcrumb: 'Wallets' } This guide is for custodial smart accounts. If you are using non-custodial smart accounts, you should use the [Sign Messages](/docs/guides/transaction-cloud/sign-messages) with Openfort's embedded signer. Signing and verifying messages for smart accounts is different than with EOAs. There are a few reasons why: - With an EOA, the address is effectively the public key of the private key used for signing. Therefore, verifying a EOA signature is as simple as [recovering](https://soliditydeveloper.com/ecrecover) the signature and compare the recovered public key with the address. - With a smart account, the address is the address of a smart contract that has no cryptographic link to the signing private key. Therefore, you must use [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271) to validate the message. - With an EOA, you don't have to deploy the account. It just exists. - Since smart accounts need to be deployed, it may not be clear how you can validate messages against a smart account not yet deployed. ### Signing messages To sign messages: ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const _domain = { name: "Openfort", version: "0.5", chainId: 13337, verifyingContract: "0x9b5AB198e042fCF795E4a0Fa4269764A4E8037D2", }; const types = { Mail: [ { name: "from", type: "Person" }, { name: "to", type: "Person" }, { name: "content", type: "string" }, ], Person: [ { name: "name", type: "string" }, { name: "wallet", type: "address" }, ], }; const mail = { from: { name: "Alice", wallet: "0x2111111111111111111111111111111111111111", }, to: { name: "Bob", wallet: "0x3111111111111111111111111111111111111111", }, content: "Hello!", }; const structHash = ethers.utils._TypedDataEncoder.hash(domain, types, mail); const signature = await openfort.accounts.signPayload({ id: "acc_4194ad24-c818-4e5c-b003-9cc2aa7df53b", hash: structHash, domain: domain value: mail, types: types, }); ``` ### Validating signatures You can validate signatures with [ERC-1271](https://eips.ethereum.org/EIPS/eip-1271). Here's an example with ethers: ```ts client.ts const ethers = require("ethers"); async function verifySignature(hash, signature, address) { let provider = new ethers.providers.JsonRpcProvider(providerUrl); const ABI = { inputs: [ { internalType: "bytes32", name: "_hash", type: "bytes32", }, { internalType: "bytes", name: "_signature", type: "bytes", }, ], name: "isValidSignature", outputs: [ { internalType: "bytes4", name: "", type: "bytes4", }, ], stateMutability: "view", type: "function", }; const iface = new ethers.utils.Interface(ABI); const encodedDataDeposit = iface.encodeFunctionData("isValidSignature", [ hash, signature, ]); const tx = { to: address, data: encodedDataDeposit, }; return await provider.call(tx); } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/advanced/social-recovery.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Use Social Recovery', description: 'Learn how to emable social recovery', subtitle: 'Learn how to set up social recovery in your game.', tocVideo: 'E8e1pklBbgw', breadcrumb: 'Smart wallets', } One of the main hurdles in enhancing gaming experiences within Web3 environments is ensuring player account security. Unlike traditional gaming accounts, where password recovery is straightforward, Web3 accounts often require meticulous management of a seed phrase to prevent loss of access. This can be a daunting task for players, necessitating either a fail-safe method to secure the seed phrase or reliance on a centralized system to handle key management. By default, Openfort is not a guardian. You need to pass the `defaultGuardian` as **true** parameter to register Openfort as a guardian when creating a new smart account when using [create account](/docs/reference/api/create-an-account-object). To address this, gaming platforms can implement a "guardian" system. Guardians are trusted entities or mechanisms designated to facilitate the recovery of a player's account. If a player misplaces their access key, they can create a new one and request their guardians to authorize this new key as the account's official access method, effectively regaining control over their account. This guardian system can be applied in two primary recovery scenarios: 1. **Self-Recovery:** Players have the option to configure their account recovery using another authentication factor they control, such as a hardware passkey or an alternative Web3 wallet. This method empowers players with direct control over their account recovery process, enhancing security and convenience. 2. **Game-Assisted Recovery:** a player might designate the game developer or platform as their guardian. In the event of losing access to their account, the player would reach out to the game's support team, who would then facilitate the account recovery on their behalf. For a general overview of social recovery, see the [Recoverable Accounts](https://www.openfort.xyz/blog/recoverable-accounts) post. ## Configure assisted recovery This guide will go through all the necessary steps to complete a recovery with Openfort as a guardian. The default implementation of the endpoint includes: - Threshold: 1:1 - Guardian: Openfort - Time lock: 2 days ### 1. Set up Openfort - Server side Use our official libraries to access the Openfort API from your application: Install Openfort: ```bash command-line npm install @openfort/openfort-node --save ``` Initialize @openfort/openfort-node: ```ts server.ts const Openfort = require('@openfort/openfort-node').default const openfort = new Openfort(YOUR_SECRET_KEY) ``` ### 2. Start recovery process Openfort will perform a Start Recovery operation to recover the account from the current owner to the new owner. The `policy` parameter is a policy that will be used to sponsor the transaction. You can find more information about policies in our [documentation](/docs/reference/api/list-policies). Bear in mind that this policy needs to have a `account_functions` policy rule to allow the sponsorship of this operation. ```bash command-line curl https://api.openfort.xyz/v1/account/acc_.../start_recovery \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d newOwnerAddress="0x416c...354D" \ -d policy="pol_..." ``` ```ts server.ts const accountId = 'acc_...'; const policy = 'pol_...'; const newOwnerAddress = '0x416c...354D'; const playerTransferOwnership = await openfort.accounts.startRecovery( { id: accountId, policy: policy, newOwnerAddress: newOwnerAddress, } ) ``` ### 3. Complete recovery After complying with the period of time `lockPeriod`, the guardian has a `securityPeriod` to confirm the proposal. In this case, Openfort will submit the needed signature to complete the recovery of the account. ```bash command-line curl https://api.openfort.xyz/v1/account/acc_.../complete_recovery \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d newOwnerAddress="0x416c...354D" \ -d policy="pol_..." ``` ```ts server.ts const accountId = 'acc_...'; const policy = 'pol_...'; const newOwnerAddress = '0x416c...354D'; const playerTransferOwnership = await openfort.accounts.completeRecovery( { id: accountId, policy: policy, newOwnerAddress: newOwnerAddress, } ); ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/advanced/transfer-ownership.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Transfer the owner of an account', description: 'Learn how to transfer the ownership of an Openfort smart contract.', subtitle: 'Learn how to transfer ownership of a smart account.', tocVideo: 'xBzl8hk__P8', breadcrumb: 'Smart wallets', } With Openfort, you can change the ownership of an account from one address to another. Your players can take ownership of their account without ever having to go through exposing a private key. Secure, frictionless, and easy. There are 2 steps involved in transferring account ownership: - **transferOwnership**: starts the ownership transfer of the contract to a new account. Called through the API and performed by Openfort. - **acceptOwnership**: the new owner accepts the ownership transfer. Performed in the client side by the new owner. Openfort accounts implement [Ownable2Step](https://docs.openzeppelin.com/contracts/4.x/api/access#Ownable2Step) from [Openzeppelin](https://www.openzeppelin.com/) to create a secure way of transferring account ownership. You can check out the code that allows for this behavior in their [GitHub repository](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable2Step.sol). For more information about how to use the sesion key endpoints, you can visit our [API documentation](/docs/reference/api/request-transfer-ownership-of-account). Check out our sample with a transfer ownership example: [GitHub source](https://github.com/openfort-xyz/samples/tree/main/ssv-social-nextjs) and [video walkthrough](https://youtu.be/xBzl8hk__P8?t=264). ## Quickstart This guide will go though all the necessary steps to transfer account ownership. ### 1. Set up Openfort - Server side Use our official libraries to access the Openfort API from your application: Install Openfort Node.js library: ```bash command-line npm install @openfort/openfort-node --save ``` Initialize '@openfort/openfort-node' with your secret key: ```ts server.ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); ``` ### 2. Request transfer ownership - Server side Openfort will perform a [`transferOwnership`](https://docs.openzeppelin.com/contracts/4.x/api/access#Ownable2Step-transferOwnership-address-) operation to transfer the ownership of the account from the current owner to the new owner. The `policy` parameter is a policy that will be used to sponsor the transaction. You can find more information about policies in our [documentation](/docs/reference/api/list-policies). Bear in mind this policy needs to have a `account_functions` policy rule to allow the sponsorship of this operation. ```bash command-line curl https://api.openfort.xyz/v1/accounts/acc_.../request_transfer_ownership \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d newOwnerAddress="0x416c...354D" \ -d "policy=pol_..." ``` ```ts server.ts const accountId = 'acc_...'; const policy = 'pol_...'; const newOwnerAddress = '0x416c...354D'; const playerTransferOwnership = await openfort.accounts.requestTransferOwnership( { id: accountId, policy: policy, newOwnerAddress: newOwnerAddress, } ); ``` ### 3. Accept account ownership - Client side Using [Wagmi](https://wagmi.sh/) React hooks, you can accept the account ownership by performing an [`acceptOwnership`](https://docs.openzeppelin.com/contracts/4.x/api/access#Ownable2Step-acceptOwnership--) operation to the account address. Find a working example of how to accept account ownership in our GitHub repository [component sample](https://github.com/openfort-xyz/samples/blob/main/ssv-social-nextjs/components/accept-ownership.tsx). Accept account ownership from client side: ```jsx accept-ownership.tsx import { usePrepareContractWrite, useContractWrite, useWaitForTransaction, } from 'wagmi' const { config } = usePrepareContractWrite({ address: accountAddress, abi: [ { inputs: [], name: 'acceptOwnership', outputs: [], stateMutability: 'nonpayable', type: 'function', }, ], functionName: 'acceptOwnership', }) const { data, write } = useContractWrite(config) const { isLoading, isSuccess } = useWaitForTransaction({ hash: data?.hash, }); ``` {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/guides/bridge.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' import { Accordion } from '@/components/ui' export const meta = { title: 'Relay.link integration', description: 'Learn how to bridge tokens in your game.', subtitle: 'Learn how to implement bridging in your app.' } The sample allows you to convert any tokens, using [Relay.link](https://relay.link/). Bridging rates are determined via the bridge provider, and depend on supply and demand of the respective tokens. ## Samples
{'A quick start guide to integrate smart accounts with Relay Link'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/guides/exchange.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' import { Accordion } from '@/components/ui' export const meta = { title: 'Uniswap V3 integration', description: 'Learn how to swapping tokens in your game.', subtitle: 'Learn how to implement swaps in your app.' } The API allows you to convert any tokens, using [Uniswap V3](https://docs.uniswap.org/sdk/v3/overview). Conversion rates are determined via an Automated Market Maker mechanism, and depend on supply and demand of the respective tokens. To exchange tokens, simply make a `POST` request to Openfort's exchange API: ``` https://api.openfort.xyz/v1/exchange ``` In the body of the request: - Include the contract addresses of the desired `tokenInAddress` and `tokenOutAddress` tokens - Include a `fromAddress` that contains the address from which the token is swapped. - Include an `amount` to swap, either a desired input and output token amount. Depending on the "direction" of the conversion, there are two different `tradeType`s, which are covered with examples below too. Let's assume we have two tokens IN and OUT: ### Converting with an exact input amount - The player wants to swap 100 IN to OUT: 1. we first need to get the amount of OUT we can expect to get for 100 IN. 2. then convert it with an `EXACT_INPUT` to make sure we get the highest amount of OUT for our 100 IN. ### Converting with an exact output amount - The player wants to buy 10 OUT: 1. here we first fetch the required amount of IN to obtain 10 OUT. 2. then convert it with an `EXACT_OUTPUT` to make sure get exactly 10 OUT. Below is a sample cURL command for generating a new wallet for a user with Openfort: ```bash command-line curl https://api.openfort.xyz/v1/exchange \ -u "$YOUR_SECRET_KEY:" \ -d 'chainId=80002' \ -d 'fromAddress="0x45..."' \ -d 'tokenInAddress="0x45..."' \ -d 'tokenOutAddress="0x45..."' \ -d 'amount="100000"' \ -d 'tradeType=EXACT_INPUT' ``` A successful response will include the new user object along with their user's ID (`playerID`), like below: ```bash json { "id": "tin_c502d628-5bb3-42f2-b8f5-62ba4d71df3a", "createdAt": 1689869074, "object": "transactionIntent", "abstractionType": "accountAbstractionV6", "details": { "userOperationHash": "0x25d3...005c", "userOperation": { "sender": "0x48930Cd730652bf0B18Ef8c80cD0Fa1Cc72A233E", "nonce": "0x2", "initCode": "0x", "callData": "0xb61d...0000", "callGasLimit": "0x27863", "verificationGasLimit": "0x16001", "preVerificationGas": "0xb818", "maxFeePerGas": "0x62590091", "maxPriorityFeePerGas": "0x62590091", "paymasterAndData": "0x3210...b51c", "signature": "0x6202...3d1b" }, }, "chainId": 80002, "updatedAt": 1689869074, "policy": { "id": "pol_..." }, "player": { "id": "pla_..." }, "account": { "id": "acc_..." }, "response": { "createdAt": 1689869074, "logs": [ { "removed": false, "transactionIndex": 0, "blockNumber": 44904492, "transactionHash": "0x25d3...005c", "address": "0x5FF1...2789", "topics": [ "0xbb47...f972" ], "data": "0x", "logIndex": 0, "blockHash": "0x8a69...6d59" } ], "blockNumber": 8789286, "transactionHash": "0x25d3...005c", "to": "0x0576...1B57", "gasUsed": "336730", "status": 1 }, "interactions": [ { "functionName": "mint", "value": "100000000000000", "contract": "0x0576...1B57", "functionArgs": [ "0x63B7...484f" ] } ] } ``` Check the [Quote Swap endpoint](https://www.openfort.xyz/docs/reference/api/quote-token-swap) to get a quotation before executing the conversion. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/connected-wallets.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Using smart wallets', breadcrumb: 'Smart wallets', } Smart wallets in Openfort are your primary interface for blockchain interactions. Once an embedded signer is set up, a smart wallet is automatically created and associated for your user. ## Getting an EIP-1193 provider All of Openfort's wallets can export a standard [EIP-1193 provider](https://eips.ethereum.org/EIPS/eip-1193) object. This allows your app to request signatures and transactions from the wallet, using familiar JSON-RPC requests like `personal_sign` or `eth_sendTransaction`. [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193), also known as the Ethereum JavaScript API, is a standardized interface for how applications can request information, signatures, and transactions from a connected wallet. To get a wallet's EIP-1193 provider, use the openfort `getEthereumProvider` method: ```tsx main.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = await openfort.getEthereumProvider(); ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` When requesting signatures and transactions from the wallet, you can either choose to interface with the **EIP-1193** provider directly, or to pass it to a library like `wagmi` or `viem`. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/funding.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Funding wallets', description: 'Simplify onnramping funds to your embedded wallet.', subtitle: 'Simplify onnramping funds to your embedded wallet.', breadcrumb: 'Smart wallets', } **Openfort makes it easy for your users to fund their wallets with a variety of assets**, including a network's native currency (e.g. ETH), USDC, and other ERC20 tokens. This makes it seamless to take onchain actions within your apps such as purchasing goods, swapping tokens, minting NFTs, and more.
control policy spending
Openfort enables users to fund their wallets by: - transferring assets from an external wallet (e.g. Rabbit Wallet) - purchasing assets from MoonPay with fiat currency - purchasing assets from Coinbase Onramp or transferring from Coinbase accounts The following are three funding methods suggested from Openfort and you can find implementations of such in our SDK. You're open though to integrate any onramp. ## External wallets The **external wallets** funding option enables users to transfer funds from an external wallet (e.g. MetaMask) to their embedded wallet within your app. With external wallets, users can fund their accounts with a network's native currency (e.g. ETH), USDC, or other ERC20 tokens. If users don't want to connect an external wallet, Openfort will also give the users to copy their embedded wallet address, and manually transfer funds from their external wallet to their embedded wallet. ## Coinbase Onramp The [Coinbase Onramp](https://www.coinbase.com/en-es/developer-platform/products/onramp) funding option enables users to purchase assets from Coinbase or transfer assets from an existing Coinbase account, directly within your app. If users have already completed KYC and identity verification with Coinbase for an existing Coinbase account, they will not need to do so again, streamlining their asset purchase/transfer experience. Please note that these purchases are not immediate and it may take a few minutes for funds to arrive in your user's wallet. With Coinbase Onramp, users can fund their accounts with a network's native currency (e.g. ETH) or USDC on Coinbase's supported networks. Note that not all payment methods are available in all regions due to local regulations. See [Coinbase's regional support guide](https://help.coinbase.com/en/commerce/getting-started/supported-payment-methods) for more information on which payment methods are supported in which regions. ## MoonPay The [MoonPay](https://www.moonpay.com/) funding option enables users to purchase assets with fiat payments including bank transfer, credit cards, and debit cards. This is particularly useful for users that may not hold crypto outside of your application and are purchasing crypto for the first time. Please note that these purchases are not immediate, and depending on the payment method selected by your users, it may take a few days for funds to arrive in your user's wallet. Generally, paying with bank transfer has the highest approval rates for cryptocurrency purchases. With MoonPay, users can fund their accounts with a network's native currency (e.g. ETH) or USDC on MoonPay's [supported networks](https://support.moonpay.com/customers/docs/list-of-supported-cryptocurrencies). Note that support for assets [varies by region](https://support.moonpay.com/customers/docs/list-of-supported-cryptocurrencies) due to local regulations. If a user attempts to purchase an asset from an unsupported region, MoonPay will allow the user to purchase any assets that are supported in their region. ---- ## Integrating a custom fiat on-ramp To start, you'll need to choose a fiat on-ramp provider that meets your app's requirements. Different on-ramp providers vary in their support of: - different tokens (ETH, USDC, Dai, POL, etc.) - different networks (Ethereum, Polygon, Optimism, etc.) - different regions (US, Europe, Brazil, South Korea, India, etc.). - different payment methods (credit cards, debit cards, ACH, instant ACH, etc. ) Once you have chosen an on-ramp provider for your app, set up an account with that provider and retrieve your sandbox API keys to build an integration. For example, after setting up a Moonpay account, you can retrieve your API keys from their developer dashboard like below: Most providers will provision you with a public API key that can be exposed to your frontend, and a secret API key that should only exist on your server. Some providers may also offer a webhook API key so you can subscribe to updates on your users' transactions. ### Integrating the provider For the remainder of this guide, we will focus on integrating Moonpay as your fiat on-ramp provider. The integration follows three main steps: 1. Collect user details in your frontend 2. Generate the Moonpay URL with proper parameters 3. Handle the purchase flow and monitor transactions ### 1. Collect User Information in Your Frontend First, we need to collect information about the user and their desired purchase. With Openfort, we can get the user's wallet address using the `useOpenfort` hook: ```typescript import { useOpenfort } from "@/hooks/useOpenfort"; import { Address } from "viem"; import { EmbeddedState } from "@openfort/openfort-js"; const { state, getEOAAddress } = useOpenfort(); const [accountAddress, setAccountAddress] = useState
(); useEffect(() => { const init = async () => { if (state !== EmbeddedState.READY) return; const accountAddress = await getEOAAddress(); setAccountAddress(accountAddress as `0x${string}`); }; init(); }, [state]); ``` For the funding amount, we can let users input their desired amount: ```typescript const [fundAmount, setFundAmount] = useState('0.02'); ``` ### 2. Generate the Moonpay URL Once we have the user's information, we can generate the Moonpay URL. You'll need your Moonpay API key for this step: ```typescript // Generate a unique transaction ID for tracking const txId = 'openfort-' + window.crypto.randomUUID(); // Construct the Moonpay URL with all necessary parameters const moonpayLink = `https://buy-sandbox.moonpay.com/` + `?externalTransactionId=${txId}` + `&apiKey=${process.env.NEXT_PUBLIC_MOONPAY_API_KEY}` + `&walletAddress=${accountAddress}` + `¤cyCode=ETH` + `"eCurrencyAmount=${fundAmount}`; ``` Important parameters in the URL: - `externalTransactionId`: A unique identifier for tracking the transaction - `apiKey`: Your Moonpay public API key - `walletAddress`: The user's wallet address - `currencyCode`: The cryptocurrency to purchase (e.g., 'ETH') - `quoteCurrencyAmount`: The amount to purchase ### 3. Redirect your user to the on-ramp URL Once you have generated the Moonpay URL, you can redirect your user to complete their purchase. The following code handles the redirection and monitors the transaction status: ```typescript const handleFund = async (service: any) => { // Update UI state to show progress setStep(StepEnum.SERVICE_PROGRESS); setService(service); // Open Moonpay in a new window window.open(service.link, '_blank'); // Start monitoring the transaction const intervalFund = setInterval( () => checkFunding(() => service.checkTxResult(service.verifyUrl)), 2000 ); intervalFundingId.current = intervalFund; }; // Function to check funding status const checkFunding = async (txResult: any) => { if (await txResult() === 'completed') { clearInterval(intervalFundingId.current); setStep(StepEnum.COMPLETED); handleSetMessage('Funds added successfully!'); } }; // Function to check transaction status const checkMoonpayTransaction = async (txId: string) => { const verifyUrl = `https://api.moonpay.com/v1/transactions/ext/${txId}?apiKey=${process.env.NEXT_PUBLIC_MOONPAY_API_KEY}`; try { const response = await fetch(verifyUrl); if (!response.ok) return 'pending'; const json = await response.json(); switch (json[0].status) { case 'completed': return 'completed'; case 'failed': return 'failed'; default: return 'pending'; } } catch (error) { console.error('Error checking transaction status:', error); return 'pending'; } }; ``` Alternatively, if you do not want to redirect the user to a new tab, you can instead surface the on-ramp URL within an **iframe** embedded within your site. **That's it! Your users can now fund the wallets they've connected/created through Openfort and take on-chain actions in your app.** export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/libraries.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Integrating with web3 libraries', description: 'Using web3 libraries to interact with wallets and smart contracts.', subtitle: 'Using web3 libraries to interact with wallets and smart contracts.', breadcrumb: 'Smart wallets', } Openfort's `wallet` object is fully compatible with popular web3 libraries for interfacing wallets, including [`ethers`](/docs/guides/transaction-cloud/integrations#ethers), and [`wagmi`](/docs/guides/transaction-cloud/integrations#wagmi). Read below to learn how to best integrate Openfort alongside these libraries. ## Ethers Ethers represents connected wallets as a [provider](https://docs.ethers.org/v5/api/providers/provider/), which can be used to take read-only actions with the wallet, and a [signer](https://docs.ethers.org/v5/api/signer/), which can be used to take write actions (signatures and transactions). Call the wallet's `getEthereumProvider` method to get a provider: ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const web3Provider = new ethers.providers.Web3Provider(provider); ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` Then, call the provider's `getSigner` method to get the corresponding signer: ```tsx const signer = web3Provider.getSigner(); ``` You can then use the [provider](https://docs.ethers.org/v5/api/providers/provider/) and [signer](https://docs.ethers.org/v5/api/signer/) to get information about the wallet or request signatures and transactions. --- ## Viem Viem represents connected wallets as a [wallet client](https://viem.sh/docs/clients/wallet) object, which you can use to get information about the current wallet or the request signatures and transactions. To get a viem wallet client for a user's connected wallet, first import your desired network from the `viem/chains` package and import the `createWalletClient` method and custom transport from `viem`: ```tsx import {createWalletClient, custom} from 'viem'; // Replace `sepolia` with your desired network import {sepolia} from 'viem/chains'; ``` Lastly, get the wallet's EIP1193 provider using the wallet's `getEthereumProvider` method and pass it to viem's `createWalletClient` method like so: ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = await wallet.getEthereumProvider(); const walletClient = createWalletClient({ chain: sepolia, transport: custom(provider), ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` You can then use the [wallet client](https://viem.sh/docs/clients/wallet) to get information about the wallet or request signatures and transactions. --- ## Wagmi [Wagmi](https://wagmi.sh/) is a set of React hooks for interfacing with Ethereum wallets, allowing you read wallet state, request signatures or transactions, and take read and write actions on the blockchain. **Openfort is fully compatible with [wagmi](https://wagmi.sh/), and you can use wagmi's React hooks to interface with external and embedded wallets from Openfort. Just follow the steps below!** Check out the [wagmi starter repo](https://github.com/openfort-xyz/openfort-js/tree/main/examples/apps/wallet-libraries/next-wagmi). Checkout the [wagmi live demo](https://wagmi.openfort.xyz). ### 1. Install dependencies Install the latest versions of `wagmi`, `@tanstack/react-query` and `@openfort/openfort-js`: ```sh npm i wagmi @tanstack/react-query @openfort/openfort-js ``` ### 2. Setup TanStack Query To start, set up your app with the [TanStack Query's React Provider](https://tanstack.com/query/v5/docs/framework/react/overview). Wagmi uses TanStack Query under the hood to power its data fetching and caching of wallet and blockchain data. ```tsx import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; ``` Next, create a new instance of the [`QueryClient`](https://tanstack.com/query/v4/docs/reference/QueryClient): ```tsx const queryClient = new QueryClient(); ``` Then, wrap your app's components with the [`QueryClientProvider`](https://tanstack.com/query/latest/docs/framework/react/reference/QueryClientProvider). This must be rendered inside the `WagmiProvider` component. ```tsx ``` For the [`client`](https://tanstack.com/query/latest/docs/framework/react/reference/QueryClientProvider) property of the `QueryClientProvider`, pass the [`queryClient`](https://tanstack.com/query/v4/docs/reference/QueryClient) instance you created. ### 3. Setup Wagmi To build your `wagmi` config, import the `createConfig` method. Next, import your app's required chains from [`viem/chains`](https://viem.sh/docs/chains/introduction.html) and the [`http`](https://wagmi.sh/core/api/transports/http#http) transport from `wagmi`. Your app's required chains should match whatever you configure as `supportedChains` for Openfort. ```tsx wagmi.tsx import { createConfig, http } from 'wagmi'; import { sepolia } from 'wagmi/chains'; import { injected } from 'wagmi/connectors'; export const config = createConfig({ chains: [sepolia], connectors: [injected()], transports: { [sepolia.id]: http(), }, }); ``` ### 4. Create Openfort Connector You'll need to create a custom connector for Openfort. Create a new file `openfortConnector.ts`: ```tsx main.tsx import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; import {WagmiProvider} from 'wagmi'; import {Connect} from './components/Connect'; import {config} from './wagmi'; import {useEffect} from 'react'; import {openfortInstance} from './main'; const queryClient = new QueryClient(); export default function App() { useEffect(() => { if (!openfortInstance) return; openfortInstance.getEmbeddedState(); openfortInstance.getEthereumProvider(); // EIP-6963 }, [openfortInstance]); return ( ); } ``` ### 5. Connector list Create a new file `Connect.tsx` to list the available connectors and handle the connection. When you press on Openfort, then you will be redirected to the authentication page that you should implement. You can find an example of the authentication page in the [Openfort documentation](https://github.com/openfort-xyz/openfort-js/blob/main/examples/apps/wallet-libraries/vite-wagmi/src/components/Authenticate.tsx). ```tsx Connect.tsx import * as React from 'react'; import {useNavigate} from 'react-router-dom'; import {Connector, useChainId, useConnect} from 'wagmi'; export function ConnectorsList() { const chainId = useChainId(); const {connectors, connect, error} = useConnect(); const navigate = useNavigate(); const [activeConnector, setActiveConnector] = React.useState(null); React.useEffect(() => { if ( error && activeConnector?.name === 'Openfort' && error.message === 'Unauthorized - must be authenticated and configured with a signer' ) { navigate('/authentication'); } }, [error, activeConnector, navigate]); const handleConnect = (connector: Connector) => { setActiveConnector(connector); connect({connector, chainId}); }; return (
{connectors .filter((connector) => !connector.name.includes('Injected')) .map((connector) => ( handleConnect(connector)} /> ))}
{error &&
Error: {error.message}
}
); } function ConnectorButton({ connector, onClick, }: { connector: Connector; onClick: () => void; }) { const [ready, setReady] = React.useState(false); React.useEffect(() => { (async () => { const provider = await connector.getProvider(); setReady(!!provider); })(); }, [connector, setReady]); return ( ); } ``` ### 6. Complete example Altogether, this should look like: ```tsx app.tsx import {QueryClient, QueryClientProvider} from '@tanstack/react-query'; import {WagmiProvider} from 'wagmi'; import {Connect} from './components/Connect'; import {config} from './wagmi'; import {useEffect} from 'react'; import {openfortInstance} from './main'; const queryClient = new QueryClient(); export default function App() { useEffect(() => { if (!openfortInstance) return; openfortInstance.getEmbeddedState(); openfortInstance.getEthereumProvider(); // EIP-6963 }, [openfortInstance]); return ( ); } ``` ```tsx main.tsx import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App.tsx'; import './index.css'; import Openfort from '@openfort/openfort-js'; import {RouterProvider, createBrowserRouter} from 'react-router-dom'; import Authenticate from './components/Authenticate.tsx'; const OPENFORT_PUBLISHABLE_KEY = 'pk_test_505bc088-905e-5a43-b60b-4c37ed1f887a'; const SHIELD_PUBLISHABLE_KEY = 'a4b75269-65e7-49c4-a600-6b5d9d6eec66'; export const openfortInstance = new Openfort({ baseConfiguration: { publishableKey: OPENFORT_PUBLISHABLE_KEY, }, shieldConfiguration: { shieldPublishableKey: SHIELD_PUBLISHABLE_KEY, }, }); const router = createBrowserRouter([ { path: '/', element: , }, { path: '/authentication', element: , }, ]); ReactDOM.createRoot(document.getElementById('root')!).render( ); ``` ```tsx wagmi.tsx import {http, createConfig} from 'wagmi'; import {sepolia} from 'wagmi/chains'; import {injected} from 'wagmi/connectors'; export const config = createConfig({ chains: [sepolia], connectors: [injected()], transports: { [sepolia.id]: http(), }, }); ``` ```tsx Connect.tsx import * as React from 'react'; import {useNavigate} from 'react-router-dom'; import {Connector, useChainId, useConnect} from 'wagmi'; export function ConnectorsList() { const chainId = useChainId(); const {connectors, connect, error} = useConnect(); const navigate = useNavigate(); const [activeConnector, setActiveConnector] = React.useState(null); React.useEffect(() => { if ( error && activeConnector?.name === 'Openfort' && error.message === 'Unauthorized - must be authenticated and configured with a signer' ) { navigate('/authentication'); } }, [error, activeConnector, navigate]); const handleConnect = (connector: Connector) => { setActiveConnector(connector); connect({connector, chainId}); }; return (
{connectors .filter((connector) => !connector.name.includes('Injected')) .map((connector) => ( handleConnect(connector)} /> ))}
{error &&
Error: {error.message}
}
); } function ConnectorButton({ connector, onClick, }: { connector: Connector; onClick: () => void; }) { const [ready, setReady] = React.useState(false); React.useEffect(() => { (async () => { const provider = await connector.getProvider(); setReady(!!provider); })(); }, [connector, setReady]); return ( ); } ```
**That's it! You've successfully integrated Openfort alongside `wagmi` in your app! 🎉** ### 7. Use `wagmi` throughout your app Once you've completed the setup above, you can use wagmi's React hooks throughout your app to interface with wallets and take read and write actions on the blockchain. To use wagmi hooks, like `useAccount`, in your components, import the hook directly from `wagmi` and call it as usual: ```tsx import {useAccount} from 'wagmi'; export default const WalletAddress = () => { const {address} = useAccount(); return

Wallet address: {address}

; } ``` ### Demo app with WAGMI Feel free to take a look at the app's source code to see an end-to-end implementation of Openfort with wagmi:
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'Wagmi template', description: 'Using Openfort accounts with wagmi.', href: 'https://github.com/openfort-xyz/openfort-js/tree/main/examples/apps/wallet-libraries/vite-wagmi', }, ] export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/smart-wallet/send.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Requesting signatures and transactions', breadcrumb: 'Smart wallets', } To request signatures or transactions from a connected wallet, you can either: - use the wallet's EIP-1193 provider to send JSON-RPC requests to the wallet directly. - pass the wallet to a library like `viem`, `ethers`, or `wagmi`. - for the embedded wallet specifically, create a `transactionIntent` from the **server** and `signMessage` it with the **embedded signer (client)**. At a high-level, the EIP-1193 provider implements a method called `request` that accepts an object with the following fields: - **`method`**: the name of a JSON-RPC request to send to the wallet - **`params`**: any parameters to include with the request ## Signatures You can choose to create the session key using a web3 libraries or using the Openfort native method. The `request` method of the EIP-1193 provider can be used to request signatures. First, get the provider: ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = openfort.getEthereumProvider(); ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` Then use the provider's `request` method with `eth_sign` or related methods: ```tsx const message = "Sign this message"; const signature = await provider.request({ method: 'personal_sign', params: [message, address] }); ``` If you've integrated Openfort with another web3 library, you can also use that library's syntax for requesting signatures from the wallet: | Library | Method | |---------|--------| | Ethers | [Use the signer's `signMessage` method](https://docs.ethers.org/v5/api/signer/#Signer-signMessage) | | Wagmi | [Use the `useSignMessage` hook](https://wagmi.sh/react/api/hooks/useSignMessage) | | Viem | [Use the `signMessage` action](https://viem.sh/account-abstraction/accounts/smart/signMessage) | To sign message with the smart wallet simply call the Openfort's `signMessage` or `signTypedData` method like so: ```tsx const signature = await openfort.signMessage({ player: "pla_...", message: "Sign this message" }); ``` ## Transactions You can choose to create the session key using a web3 libraries or using the Openfort native method. Get the provider and optionally configure [gas policy](/docs/guides/dashboard/gas-sponsorship) to make a sponsored transaction: ```tsx client.tsx import openfort from "./openfortConfig" // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const provider = await openfort.getEthereumProvider({ policy: 'pol_...', } ``` ``` openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` Then, using the provider's `request` method, send a [`eth_sendTransaction`](https://docs.metamask.io/wallet/reference/eth_sendtransaction/) JSON-RPC to the wallet. In the `params` array, include as the first entry an object containing the transaction's parameters, such as **to**, **value**, **data**, **gasLimit**, **maxPriorityFeePerGas**, **maxFeePerGas**, and **gasPrice**. ```tsx const transactionRequest = { to: '0xRecipientAddress', value: 100000, }; const txHash = await provider.request({ method: 'eth_sendTransaction', params: [transactionRequest], }); ``` See [these docs](https://docs.metamask.io/wallet/reference/eth_sendtransaction/) for the parameters that can be passed in `eth_sendTransaction`. You do not need to specify from as we populate it from the user's connected wallet, and you can pass either a number, bigint, or a hexadecimal string into the value parameter. If you've integrated Openfort with another web3 library, you can also use that library's syntax for sending transactions from the wallet: | Library | Method | |---------|--------| | Ethers | Use the signer's [`sendTransaction` method.](https://docs.ethers.org/v5/api/signer/#Signer-sendTransaction) | | Wagmi | Use the [`useSendTransaction` hook.](https://wagmi.sh/react/api/hooks/useSendTransaction) | | Viem | [`sendTransaction` action](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation) | ## Smart Contracts Calling a smart contract is a special case of sending a transaction. To call a smart contract, you should send a transaction with the following parameters: - **`to`**: the address of the smart contract to call - **`data`**: the encoded function call data - **`value`**: any value to send (for payable functions) To prepare the calldata for a smart contract interaction, we recommend using viem's [encodeFunctionData](https://viem.sh/docs/contract/encodeFunctionData#encodefunctiondata) method, like so: ```tsx import { encodeFunctionData } from 'viem'; const data = encodeFunctionData({ abi: contractAbi, functionName: 'methodName', args: [arg1, arg2] }); ``` You can then [send a transaction](/docs/guides/transaction-cloud/send#transactions) from the wallet as normal, and pass the calldata in the **`data`** field of the transaction request: ```tsx const transactionRequest = { to: '0xTheContractAddress', data: data, value: 100000, // Only necessary for payable methods }; const txHash = await provider.request({ method: 'eth_sendTransaction', params: [transactionRequest] }); ``` ## Batched transactions Smart wallets support sending a batch of transactions in a single, atomic submission to the network. To send a batched transactions with a smart wallet, call the `wallet_sendCalls` method with a calls array the transactions to batch together. As an example, you might batch together a transaction to approve a USDC spender and to transfer USDC like so: ```tsx const transactionRequest = { to: '0xTheContractAddress', data: data, value: 100000, // Only necessary for payable methods }; const txHash = await provider.request({ method: 'wallet_sendCalls', params: [ { calls: [ // Approve transaction { to: USDC_ADDRESS, data: encodeFunctionData({ abi: USDC_ABI, functionName: 'approve', args: ['insert-spender-address', BigInt(1e6)], }), }, // Transfer transaction { to: USDC_ADDRESS, data: encodeFunctionData({ abi: USDC_ABI, functionName: 'transfer', args: ['insert-recipient-address', BigInt(1e6)], }), }, ], }, ], }); ``` If you've integrated Openfort with another web3 library, you can also use that library's syntax for sending batched transactions from the wallet: | Library | Method | |---------|--------| | Wagmi | Use the [`useWriteContracts` hook.](https://wagmi.sh/react/api/hooks/useWriteContracts#usewritecontracts) | | Viem | [`sendCalls` action](https://viem.sh/experimental/eip5792/sendCalls) | ### 1. Create a transaction- Server side Create a request to your backend to create a transaction. In the body of the request: - Include the `player` that signs the transaction. - Include the `policy` that interacts with the contract for gas. If non-existent the user will need to have gas tokens. - Include `optimistic` if you want the transactions to be confirmed faster. Depending on the type of transaction you're creating you'll define `interactions`. The `interactions` field is an array of objects that contain the information of the contract to interact with, the function to call, and the arguments to pass to the function. - the interactions field contains the `contract` that has previously been added to Openfort. - the `functionName` defines the function to call from within the contract. - If there exist more than one function with the same name, the `functionArgs` will be used to determine which function to call. ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_..." \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][contract]"="con_..." \ -d "interactions[0][functionName]"="mint" \ -d "interactions[0][functionArgs][0]"="0x63B7...484f" ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const contractId = "con_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_mint = { contract: contractId, functionName: "mint", functionArgs: [playerId], }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_mint], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string contractId = "con_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionMint = new Interaction ( contract: contractId, functionName: "mint", functionArgs: new List { playerId } ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, optimistic: optimistic, interactions: new List { interactionMint } ); await client.TransactionIntents.Create(transactionIntentRequest); ``` Send the value of native tokens in the smallest denomination of the native currency i.e. wei (10^18) and as a `string`. The `to` parameter accepts: - any valid account `address` e.g. 0x680d2719F09B23F644c136Ab7336D42b6a76AdcC - a player `id` e.g. pla_... - an account `id` e.g. acc_... ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_..." \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][value]=1000" \ -d "interactions[0][to]=pla_..." ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_transfer = { value: "100", to: playerId }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_transfer], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionTransfer = new Interaction ( value: "100", to: playerId ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, externalOwnerAddress: null!, optimistic: optimistic, confirmationBlocks: 0, interactions: new List { interactionTransfer} ); await client.TransactionIntents.Create(transactionIntentRequest); ``` The `policy` used to sponsor a transaction that sends native tokens should have the `account_functions` policy rule. For a useful resource for computing the Wei, you can visit the [wei calculator](https://eth-converter.com/). Smart accounts support batching transactions, allowing multiple actions to be rolled into one. This feature significantly simplifies Web3 interactions for your users. For example, instead of executing `approve()` and then `transfer()`, your user can perform both in a single transaction. Batching transactions offers several key benefits: - Users only wait for one transaction to complete instead of multiple. - Users save on gas fees. - If any transaction in the batch fails, the entire batch reverts, preventing users from ending up in an inconsistent state. This characteristic is known as "atomicity." Fore security reasons, there is a limit of 9 interactions per transaction intent. To execute a batch transaction, you can send a transaction intent with **multiple interactions**, and each interaction will be executed in the order they are received. Openfort systems check the contract's ABI to find a function signature based on the `functionName` that you provide and the number of `functionArgs`. In the case that, in your contract, you have multiple functions with the same `functionName` and number of arguments, you can also include the `functionName` together with the argument types e.g. mint(address) ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_...", \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][contract]=con_..." \ -d "interactions[0][functionName]=mint" \ -d "interactions[0][functionArgs][0]=0x63B7...484f" \ -d "interactions[1][contract]=con_..." \ -d "interactions[1][functionName]=transfer" \ -d "interactions[1][functionArgs][0]=0x32B7...213d" ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const contractId = "con_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_mint = { contract: contractId, functionName: "mint", functionArgs: [playerId], }; const interaction_transfer = { contract: contractId, functionName: "transfer", functionArgs: [playerId], }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_mint, interaction_transfer], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string contractId = "con_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionMint = new Interaction ( contract: contractId, functionName: "mint", functionArgs: new List { playerId } ); var interactionTransfer = new Interaction ( contract: contractId, functionName: "transfer", functionArgs: new List { playerId } ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, externalOwnerAddress: null!, optimistic: optimistic, confirmationBlocks: 0, interactions: new List { interactionMint, interactionTransfer} ); await client.TransactionIntents.Create(transactionIntentRequest); ``` ### 2. Sign the transaction with the embedded signer. - Client side Use the `nextAction` returned by the backend to sign the transaction with the embedded signer. The transaction will be automatically signed and broadcasted by using the `sendSignatureTransactionIntentRequest` method. ```js const handleCollectButtonClick = async () => { const collectResponse = await fetch(`https://your-backend.com/api/mint`, { method: "POST", headers: { "Content-Type": "application/json", }, }); const collectResponseJSON = await collectResponse.json(); if (collectResponseJSON.data?.nextAction) { // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` const response = await openfort.sendSignatureTransactionIntentRequest( collectResponseJSON.data.id, collectResponseJSON.data.nextAction.payload.userOperationHash ); console.log("response", response); } console.log("success:", collectResponseJSON.data); }; ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/auth.mdx --- import Layout from '@/layouts/DefaultLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { id: 'auth', title: 'Authentication', description: 'Use Openfort to authenticate and create non-custodial accounts', subtitle: 'Use Openfort to authenticate and create non-custodial accounts.', breadcrumbs: 'Authentication', } At a high-level, onboarding users onchain breaks down into three core questions: who is taking the onchain action (the user), through what means are they able to control this action (the signer) and where is the affected state (the account). **With Openfort, your app can authenticate users across web2 and web3 accounts, including:** - **Email**, via password recovery - **Wallet**: via Sign In With Ethereum ([SIWE](https://eips.ethereum.org/EIPS/eip-4361)) standard - **Web2 social accounts**: via [OAuth2.0 Protocol](https://oauth.net/2/) (Google, Facebook, Twitter, Discord & more.) These methods can be configured as either login or [link](/docs/guides/javascript/auth/user-management) options for users. Once authenticated, Openfort creates a common player object that includes the user's ID (`playerID`) and all linked accounts, treating all users equally regardless of their authentication method. The Openfort Auth can be plugged into any front-end/user interface you already have. ### Guides
{'Learn how to authenticate users with email.'} {'Create a non-custodial signer for your users.'} {'Create session keys with smart wallets'}
### Templates
{'Openfort comlete sample solution for NextJS.'} {'Integration with an external signer like Web3Auth.'} {'Integration with thirdparty auth proividers like Firebase.'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/faqs.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'faqs', title: 'FAQs', description: 'Most frequently asked questions about the Openfort platform.', } ### What is an embedded wallet? An embedded wallet is a in-app wallet designed to onboard both web2 and web3 users simultaneously. Nexus includes several core components: - Authentication: A single-sign on authentication experience with familiar social logins - Signer: An embedded signer accessible across all devices and games - Account: The asset layer, powering users onchain to manage their assets ### How is an embedded wallet different to existing web3 wallets? Unlike browser extension wallets like MetaMask, which can be challenging for users to set up, or "embedded signers" that are limited to a single application, Openfort Identity offers a balance of user-friendliness and versatility. Openfort Identity allows users to use the same wallet across all their games and marketplaces, rather than having one wallet per game. ### How does an embedded wallet's key management work? Openfort uses a smart contract wallet system on EVM chains. Transactions are processed only if they're signed by either the player (embedded signer) or the game (session key). - Private key: Using an SSS approach to split the key in three shards only to be reconstructed on the player's client side. - Session key: Temporary key used created by the player authorizing a third party to make transactions under a scooped permission set. ### What platforms does embedded wallet support? | Functionality | Web | Unity | Unreal | PlayStation | Xbox | |:--------------:|:---:|:-----:|:------:|:-----------:|:----:| | Authentication | Yes | Yes | Yes | No | No | | Transactions | Yes | Yes | Yes | No | No | ### What types of providers does authentication support? Openfort supports familiar social logins and passwordless email sign-in. You can also import a custom auth token or a OIDC compatible token. ### Can users export their wallet private keys? Yes, you can use the endpoints provide to [export the private key](/docs/guides/javascript/embedded-signer/export-key). ### How does wallet recovery work with Openfort? With Openfort you can recover the account if you forget your email/social login as long as you have a majority of 2/3 key shards. In the event of not having the majority of shards, we've implemented a [social recovery](/docs/guides/javascript/smart-wallet/advanced/social-recovery) where the private key can be reconstructed. ### Can a user change their associated email address for a pre-generated wallet? No, a user cannot change their email address once they have created a pre-generated wallet. If they need to change their email address, they will need to create a new wallet. ### How will embedded wallets integrate with existing authentication or account systems? **Option 1: Full Authentication & Signer.** If you're starting from scratch, a very common way to use Nexus is as your game's primary identity and wallet (as games like Rogue Nation do). **Option 2: Existing Authentication & Signer.** However, many games will already have an account system that they will be reluctant to migrate away from. Easy solution, integrate your authentication with Nexus while using the signer solution. **Option 3: Existing Authentication & Existing Signer.** You might be already using a wallet provider and want to upgrade to smart accounts. ### What level of support and Service Level Agreements (SLAs) are provided? At Openfort, we understand the significance of maintaining a high standard of service. Our Service Level Agreements (SLAs) reflect our commitment to providing a reliable, efficient, and safe environment for your operations. ## Security and Contingency Planning ### If Openfort were to shut down with a one-month notice, would there be scope to change the signer on the Smart Contract Wallet and use it in connection with a different provider that manages the private keys differently? **TLDR:** With enough time, transitioning is fairly simple. You’d need to invoke the `transferOwnership` function for users to accept the new signer. **Detailed Answer:** Yes, if Openfort shuts down with a one-month notice, it's possible to change the signer. Since Openfort wallets are non-custodial, users have control over their private keys. The key migration process would involve using the "recovery share" and "device share" from Shamir's Secret Sharing (SSS) to reconstruct the private key, allowing users to accept a new signer through the `transferOwnership` function. The new provider would need to support compatible key management systems. ### If Openfort were shut down with zero notice, would there be any scope to do a migration? Would that rely on a self-hosted Shield for the recovery share and the device share being intact? **TLDR:** If there is no self-hosted option, users should rely on on-chain social recovery. **Detailed Answer:** Migration is still possible, but it depends on the self-hosted Shield for the recovery share and the availability of the device share. If a self-hosted Shield is not in place, users can utilize on-chain social recovery. As long as the device share and recovery share are intact, users can reconstruct their private key and migrate to a new provider. On-chain social recovery can also help recover the wallet if the device share is lost. ### If Openfort's API were compromised, what is the risk there? Can that risk be mitigated? What’s the risk of the auth share on the private key being exposed? **TLDR:** Both Openfort's server and Shield are encrypted. Even if an attacker obtains the auth share, they would need a secret to decrypt it. **Detailed Answer:** If Openfort's API were compromised, the risk is limited because both the auth share and Shield service are encrypted. Even if an attacker gains access to the auth share, they would still need to decrypt it using a secret. Furthermore, since the private key is split using Shamir's Secret Sharing, the auth share alone is insufficient to reconstruct the full key without the device or recovery share. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/features.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'features', title: 'Features', description: 'Openfort features', } This is a non-exhaustive list of features that Openfort provides for every project out of the batch. - Openfort provides the **headless smart account**, this means the wallet is in the backend of the game and let's you decide your ideal stack to work with it. - Openfort accounts offer **non-custodial accounts** by design. If you're cmong from custodial or external solutions, you can transfer the ownership of the accounts that hold the assets to external signers. All natively on the blockchain without having to export a private key. - Openfort plugs-in your **existing authentication** infrastructure or **provides you with one** in order to authenticate. - Openfort smart accounts allow players to authorize and **sign transactions without pop-ups**, all happening locally on their front-end and securely. - Openfort offers **gasless transactions** (native and ERC-20 token gas payments). ## Authentication ### Onboarding users Cusomize your onboarding experience with email, socials or wallet by connecting ouur endpoints. [Docs](/docs/guides/auth/). ### Custom Auth Offer non-custodial accounts on top of your already created authentication solution. [Docs](/docs/guides/dashboard/custom-auth/auth-token). ## Embedded Signer These services allow gamers to authenticate through various third-party providers, ensuring seamless cross-platform play. [Docs](/docs/guides/wallets). ## Account abstraction ### Sponsored Transactions Every transaction can be fully sponsored based on predefined conditions. [Docs](/docs/guides/transaction-cloud/send). ### Pay gas in ERC-20 tokens You can charge users for the gas cost in any ERC-20 token. [Docs](/docs/guides/dashboard/gas-erc20). ### Transfer account ownership Export your gaming account to any wallet of choice in once single click. [Docs](/docs/guides/transaction-cloud/accounts/transfer-ownership). ### Scoped preapproved transactions Usually referred as session keys, enable popupless preapproved transactions. [Docs](/docs/guides/transaction-cloud/accounts/session-keys). export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/react-native.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Build with React Native', subtitle: 'Get started with Openfort in your React Native project', } ## 1. Install Required Dependencies Install the latest version of the [Openfort React Native SDK](https://www.npmjs.com/package/@openfort/react-native) and its required dependencies: ```sh Terminal # Install Openfort React Native SDK yarn add @openfort/react-native # Install required dependencies yarn add buffer react-native-crypto react-native-get-random-values react-native-randombytes stream-browserify react-native-mmkv ``` ## 2. Configure Metro Create or update your `metro.config.js` to include the necessary Node.js module shims: ```javascript // metro.config.js const { getDefaultConfig } = require('expo/metro-config'); module.exports = (() => { const config = getDefaultConfig(__dirname); // Add shims for Node.js modules config.resolver.extraNodeModules = { crypto: require.resolve('react-native-crypto'), stream: require.resolve('stream-browserify'), buffer: require.resolve('buffer'), }; return config; })(); ``` ## 3. Set up auth providers Navigate to the **auth providers** page on the [Openfort dashboard](https://dashboard.openfort.xyz) by selecting your project and clicking Auth Providers Methods in the side bar in the [players page](https://dashboard.openfort.xyz/players). Select the account types you'd like users to be able to login with. ## 4. Get your Openfort keys From the [Openfort Dashboard](https://dashboard.openfort.xyz), select your desired app and navigate to the [developers page](https://dashboard.openfort.xyz/developers/api-keys). You'll need: - **Publishable Key**: Safe to expose in client-side environment - **Secret Key**: Must be kept secure and used only server-side - **Shield Keys**: Required for non-custodial wallets - Create Shield keys in the Shield section - Securely store the encryption share shown in the one-time popup - You'll get both a Publishable and Secret Shield key ## 5. Configure your app ### Import Polyfills First, import the Openfort React Native polyfills at the top of your app: ```javascript import "@openfort/react-native/polyfills"; ``` ### Set up the WebView Add the Openfort Communication WebView to your app's root layout: ```typescript // app/_layout.tsx import { OpenfortCommunicationWebView } from '@openfort/react-native'; export default function RootLayout() { return ( <> ); } ``` ### Initialize Openfort Configure the Openfort SDK with your keys: ```typescript import Openfort from "@openfort/react-native"; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", } }); ``` Because we use `mmkv` storage, expo-go will not work. Use `expo run:ios` or `expo run:android` to run your app. ## Next Steps Now that you've configured your app, you can use `openfort` throughout to access the Openfort SDK. Check out our [starter repo](https://github.com/openfort-xyz/react-native-auth-sample) to see a complete integration. export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/resources.mdx --- import Layout from '@/layouts/DefaultLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Browse sample projects', description: 'Resources for getting started building with Openfort.', subtitle:'Discover resources and samples from Openfort', } Explore the library of sample projects using Openfort. Find even more samples in our [GitHub repository](https://github.com/openfort-xyz/samples#readme). ## Samples
{'Openfort Auth Sample in a NextJS project.'} {'Wagmi sample with embedded signer.'} {'Third-party auth with embedded signer.'}
## Templates
{'Use Openfort to build a Telegram mini-app.'} {'Build Frames and make transactions onchain with Openfort.'} {'Discover how Lost Dungeon (Openfort game) is built.'}
Implemented your own library or an example you'd like to share? Send a link to your code to support@openfort.xyz and we'll be happy to add it to the list! export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/troubleshooting.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'JavaScript SDK Troubleshooting', description: 'The Openfort SDK for JavaScript helps you integrate your game.' } ## Table of Contents 1. [Vite Build Errors](#vite-build-errors) 2. [Webpack Build Errors](#webpack-build-errors) 3. [Next.js Build Errors](#nextjs-build-errors) 4. [Support](#support) ## Vite Build Errors ### Q: I'm getting warnings like "Module "buffer" has been externalized for browser compatibility" when building with Vite. How do I fix this? A: This issue is caused by missing Node polyfills in your bundled web application. To resolve it: 1. Install `vite-plugin-node-polyfills`: ```bash npm i --save-dev vite-plugin-node-polyfills # or yarn add --dev vite-plugin-node-polyfills ``` 2. Update your `vite.config.js` or `vite.config.ts`: ```javascript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { nodePolyfills } from 'vite-plugin-node-polyfills' export default defineConfig({ plugins: [ react(), nodePolyfills() ], }) ``` 3. Restart your development server. ### Q: I'm getting a "Cannot read properties of undefined (reading 'from')" error in hdkey-without-crypto.js. How do I fix this? A: This error is related to the `ethereum-cryptography` package. To fix it: 1. Install the `buffer` package: ```bash npm install buffer # or yarn add buffer ``` 2. Update your `vite.config.ts`: ```javascript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { nodePolyfills } from 'vite-plugin-node-polyfills' export default defineConfig({ plugins: [ react(), nodePolyfills({ globals: { Buffer: false } }) ], define: { global: {}, }, }) ``` 3. Restart your Vite dev server. ### Q: I'm getting a "require is not defined" error when using `vite preview`. How do I fix this? A: Add the following to your `vite.config.ts` file: ```javascript export default defineConfig({ // ... your existing config build: { commonjsOptions: { transformMixedEsModules: true } }, }) ``` Then rebuild your project before running `vite preview`. ## Webpack Build Errors ### Q: I'm getting "Module not found" errors for Node.js core modules when using create-react-app. How do I fix this? A: This is due to Webpack 5 not including Node.js polyfills by default. To fix it: 1. Install required packages: ```bash npm install --save-dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process # or yarn add --dev react-app-rewired crypto-browserify stream-browserify assert stream-http https-browserify os-browserify url buffer process ``` 2. Create a `config-overrides.js` file in your project root: ```javascript const webpack = require('webpack'); module.exports = function override(config) { const fallback = config.resolve.fallback || {}; Object.assign(fallback, { crypto: require.resolve('crypto-browserify'), stream: require.resolve('stream-browserify'), assert: require.resolve('assert'), http: require.resolve('stream-http'), https: require.resolve('https-browserify'), os: require.resolve('os-browserify'), url: require.resolve('url'), }); config.resolve.fallback = fallback; config.plugins = (config.plugins || []).concat([ new webpack.ProvidePlugin({ process: 'process/browser', Buffer: ['buffer', 'Buffer'], }), ]); config.module.rules.push({ test: /\.m?js/, resolve: { fullySpecified: false, }, }); return config; }; ``` 3. Update your `package.json` scripts: ```json "scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-scripts eject" } ``` ### Q: How do I deal with 'failed to parse source map' warnings? A: You can disable these warnings by adding `GENERATE_SOURCEMAP=false` to your start script in `package.json`: ```json "scripts": { "start": "GENERATE_SOURCEMAP=false react-app-rewired start", // ... }, ``` ## Next.js Build Errors ### Q: I'm getting a "Named export 'curves' not found" error with the elliptic package in Next.js 13/14. How do I fix this? A: Add the following to your `next.config.js`: ```javascript const nextConfig = { // ... other next config experimental: { esmExternals: false, }, }; ``` ### Q: I'm having issues importing SDK modules in Next.js 13 with the App Router. What should I do? A: Use the SDK Code Splitting method for imports: ```typescript import Openfort from '@openfort/openfort-js'; ``` ### Q: I'm getting a "Cannot read properties of undefined (reading 'fromMasterSeed')" error in Next.js 12. How do I fix this? A: Add the following to your `next.config.js`: ```javascript const nextConfig = { // ... other next config experimental: { esmExternals: false, }, }; ``` ### Q: I'm getting a "Could not detect network" error on Next.js 14 API endpoint with JsonRpcProvider. How do I fix this? A: You have three options: 1. Downgrade to Next.js 13 2. Upgrade to Ethers v6 3. Use the solution provided [in this GitHub issue discussion](https://github.com/ethers-io/ethers.js/issues/3952#issuecomment-1698913553) export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/use-openfort.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'features', title: 'Using the Openfort SDKs', } There are **two** steps to configure Openfort's embedded wallets in your application: - Configure the embedded signer configuration. - Wait for the embedded signer to be ready. ## Embedded signer configuration The Openfort SDKs provide a way to configure a non-custodial embedded signer that can be used to sign transactions and interact with the blockchain. The **`configureEmbeddedSigner`** is the method responsible for setting up and creating the non-custodial wallet. ```ts config.ts import { ShieldAuthType } from '@openfort/openfort-js'; import openfort from "./openfortConfig" // This example assumes that the user is `authenticated` async function configure(password:string, auth_token:string){ const chainId = 80002; const shieldAuth = { auth: ShieldAuthType.OPENFORT, token: auth_token, }; await openfort.configureEmbeddedSigner(chainId, shieldAuth, password); } ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", shieldEncryptionKey: "YOUR_SHIELD_ENCRYPTION_SHARE", }, }); export default openfort; ``` The `configureEmbeddedSigner` will include a `chainID` parameter, which is the identifier of the blockchain network you want to interact with and create an embedded signer there. You can read the list of supported chains [here](/docs/chains). Let's go over the rest of the `shieldAuth` parameters of the `configureEmbeddedSigner` method: | Parameter | Description | |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | auth | Defines how the `token` parameter is going to be verified. Can be either **openfort** or **custom**, defining if the token is going to be verified by Openfort or by another backend. | | token | The `access_token` or `id_token` that will be used to verify that the user is logged in in your application. | **Automatic embedded signer creation**: to offer a frictionless onboarding, you can enlable automatic embedded signer creation. Learn more about it [how to enable automatic recovery](/docs/guides/javascript/embedded-signer/recovery). ## Waiting for ready When calling `configureEmbeddedSigner`, the SDK will go through a series of states before it is ready to be used. These states are represented by the enum: | State | Description | |-----------------------------------------|------------------------------------------------------------------------| | **0** - NONE | The initial state of the SDK. | | **1** - UNAUTHENTICATED | Before the user is authenticated. | | **2** - EMBEDDED_SIGINER_NOT_CONFIGURED | Before calling the `configureEmbeddedSigner`. | | **3** - CREATING_ACCOUNT | If no account exists for the current chainID, when it will be created. | | **4** - READY | The embedded signer is ready to be used | **As a consequence, it's important to wait until the `embeddedState` has finished initializing before you use the embedded signer**, to ensure that the state you consume is accurate and not stale. To determine whether the Openfort SDK has initialized the embedded signer, you can call the method `getEmbeddedState` and check if the state is `READY`: ```ts main.ts import openfort from "./openfortConfig" const state = openfort.getEmbeddedState() ``` ```ts openfortConfig.ts import Openfort from '@openfort/openfort-js'; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", }, }); export default openfort; ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/javascript/wallets.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { breadcrumb: 'Wallets', id: 'wallets', title: 'Overview of smart wallets', } Embedded signers are non-custodial wallets provided by Openfort, seamlessly integrated into your application. They don't require a separate wallet client, such as a browser extension or mobile app, and are accessible directly from your product. These wallets are ideal for users who don't have or don't want to connect an external wallet.
Openfort Signer
## Embedded signers Embedded signers are sekf-custodial wallets provisioned by Openfort itself for a wallet experience that is directly embedded in your application. Embedded signers do not require a separate wallet client, like a browser extension or a mobile app, and can be accessed directly from your product. These are primarily designed for users of your app who may not already have an external wallet, or don't want to connect their external wallet. You can choose exactly when to create an embedded signer for your user, and can request signatures and transactions from the wallet using Openfort's native signature and transaction methods, using the wallet's EIP1193 provider, or a library like `wagmi` or `viem`. At Openfort we develop headless embedded wallets that's why we call it embedded signers which is technically a more precise way to call the embedded wallet we provide. ## Smart wallets **Every Openfort embedded signer has a smart wallet associated**. Smart wallets are *programmable*, onchain accounts that incorporate the features of [account abstraction](https://ethereum.org/en/roadmap/account-abstraction/). With just a few lines of code, you can create smart wallets for your users to sponsor gas payments, send batched transactions, and more. Under the hood, a smart wallet is an [ERC-4337-compatible](https://www.erc4337.io/) smart contract deployed onchain. This smart contract can be programmed to support features like transaction batching, gas sponsorship, delegating permissions, and more. When using a smart wallet, a user's assets are held by the smart contract itself. This smart contract is controlled by an embedded signer (an externally-owned account) secured by Openfort's non-custodial wallet infrastructure. Openfort automatically takes care of creating signers for users and generating smart contract wallets controlled by these signers. ### Gas sponsorship With smart wallets, your app can pay for gas fees simply by [registering policy](/docs/guides/dashboard/gas-sponsorship) in the [Openfort Dashboard](https://dashboard.openfort.xyz). Openfort will automatically route gas payments from your policye instead of your users' wallets, allowing your users to transact on-chain instantly –– even if they don't have a balance in their smart wallet. ### Permissions & session keys Openfort works closely with the teams building the next generation of account abstraction standards on top of ERC-4337, such as permissions & session keys ([ERC-7715](https://ethereum-magicians.org/t/erc-7715-grant-permissions-from-wallets/20100)), smart wallet modules ([ERC-7579](https://erc7579.com/)), and smart account discovery ([ERC-7555](https://ethereum-magicians.org/t/erc-7555-single-sign-on-for-account-discovery/16536)) across different applications. As these standards become ratified, Openfort will incorporate native support for these features. export const Page = ({ children }) => export default Page --- File: /pages/guides/server/quickstarts/api.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import StepHikeCompact from '@/components/StepHikeCompact' export const meta = { title: 'Backend wallet with Rest API', subtitle: 'Use a backend wallet to transfer an asset using Rest API.', breadcrumb: 'Server', hideToc: true, } You can also request Openfort's REST API directly to use backend wallets. When requesting the REST API directly, you must set certain headers on your requests. [Open your project](https://dashboard.openfort.xyz) in the Openfort Dashboard and grab your secret key from the [project settings](https://dashboard.openfort.xyz/developers/api-keys). All API requests must be authenticated using your secret key. Include it in the Authorization header using Basic auth. ```bash Terminal # Export your secret key as an environment variable export YOUR_SECRET_KEY=sk_test_... # Test the API connection curl https://api.openfort.xyz/v1/tokens \ -u "$YOUR_SECRET_KEY:" ``` Backend wallet (`dac`) can be used for escrow, minting, and transferring assets. Create a new custodial Backend wallet using the API. The response will include the backend wallet ID (starts with `dac_`) and its blockchain address. ```bash Terminal curl https://api.openfort.xyz/v1/settings/developer_accounts \ -u "$YOUR_SECRET_KEY:" \ -d name="Transfer Account" ``` Add your token contract to Openfort. This example uses a simple ERC-20 contract with transfer functionality. Save the returned contract ID (starts with `con_`) for the next step. ```bash Terminal curl https://api.openfort.xyz/v1/contracts \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d address="0x2522F4Fc9aF2E1954a3D13f7a5B2683A00a4543A" \ -d abi=[ { "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transfer", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "nonpayable", "type": "function" } ] \ -d name="Example Token" ``` Create a transaction intent to transfer tokens using your backend wallet. Replace: - `dac_...` with your Backend wallet ID - `con_...` with your contract ID - `pla_...` with the recipient's player ID - The amount with your desired transfer amount in wei (the example shows 1 token with 18 decimals) Setting `optimistic=true` means the response will be returned after simulation but before on-chain confirmation. ```bash Terminal curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d 'account=dac_...' \ -d optimistic=true \ -d 'interactions[0][contract]=con_....' \ -d 'interactions[0][functionName]=transfer' \ -d 'interactions[0][functionArgs][0]=pla_...' \ -d 'interactions[0][functionArgs][1]=1000000000000000000' ``` You can check the status of your transaction using the transaction intent ID returned in the previous step. The response will include the transaction hash and status once the transaction is processed. ```bash Terminal curl https://api.openfort.xyz/v1/transaction_intents/tin_... \ -u "$YOUR_SECRET_KEY:" ``` export const Page = ({ children }) => ( ) export default Page --- File: /pages/guides/server/quickstarts/sdk.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import StepHikeCompact from '@/components/StepHikeCompact' export const meta = { title: 'Backend wallet with SDK (Node.js)', subtitle: 'Use a backend wallet to mint an asset with NodeJS.', breadcrumb: 'Server', hideToc: true, } You can use backend wallets via Openfort's NodeJS Server SDK (or .net). Follow the instructions below to configure your desired integration. [Open your project](https://dashboard.openfort.xyz) in the Openfort Dashboard. The latest version of the Openfort Node.js server-side SDK supports Node.js versions 14+. ```bash Terminal mkdir openfort-tutorial cd openfort-tutorial npm init -y npm install @openfort/openfort-node --save touch index.js ``` After your project is ready, grab your secret_key from the [project settings](https://dashboard.openfort.xyz/developers/api-keys). Create a `.env` file and populate it with your project's secret key. ```text .env YOUR_SECRET_KEY=sk_test_... ``` ```json package.json { "name": "node", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "node index.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@openfort/openfort-node": "^0.6.10" } } ``` Backend wallet (`dac`) can be used for escrow, minting, and transferring assets. You can create a new custodial backend wallet or add your own external account by providing a signature and address. ```js index.js const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(process.env.YOUR_SECRET_KEY); const main = async () => { // Create a new custodial backend wallet const developerAccount = await openfort.settings.createDeveloperAccount({ name: "Minting Account" }); console.log("Success! Here is your backend wallet id: " + developerAccount.id); }; main().then(() => process.exit(0)); ``` We'll use a simple [ERC-721](https://eips.ethereum.org/EIPS/eip-721) contract on the [Polygon Amoy network](https://www.oklink.com/amoy/). Once added, Openfort will return a contract id that starts with `con_`. ```bash Terminal curl https://api.openfort.xyz/v1/contracts \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d chainId=80002 \ -d address="0x2522F4Fc9aF2E1954a3D13f7a5B2683A00a4543A" \ -d abi=[ { "inputs": [ { "internalType": "address", "name": "_to", "type": "address" } ], "name": "mint", "outputs": [], "stateMutability": "nonpayable", "type": "function" } ] \ -d name="Simple NFT" ``` Use your backend wallet to mint an NFT. The wallet will be used to pay for gas fees. Make sure to replace the contract id with your own. ```js index.js const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(process.env.YOUR_SECRET_KEY); const main = async () => { const developerAccount = await openfort.settings.createDeveloperAccount({ name: "Minting Account" }); const contractId = "con_..."; const chainId = 80002; const optimistic = false; const tokenId = '1'; // Token ID to mint, should be unique const interaction_mint = { contract: contractId, functionName: "mint", functionArgs: [developerAccount.address, tokenId], }; const transactionIntent = await openfort.transactionIntents.create({ "account": developerAccount.id, "chainId": chainId, "optimistic": optimistic, "interactions": [interaction_mint] }); console.log("Success! Here is your transactionIntent id: " + transactionIntent.id); }; main().then(() => process.exit(0)); ``` You're all set! Run the development server on your Terminal. You can check the transaction details in your [dashboard](https://dashboard.openfort.xyz/dashboard). ```bash Terminal npm run dev ``` export const Page = ({ children }) => ( ) export default Page --- File: /pages/guides/server/access-token.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'User Session (JWT/Authorization)', breadcrumb: 'Server', } ## Getting a user's access token from a request When your app frontend sends a request to your server, you should include the current user's access token in the Authorization header of the request. This allows your backend to securely identify the requesting user and gate API routes based on their authentication status, their user ID, and more. This guide assumes you have already configured your frontend to including users' access tokens in requests to your server. If this is not the case, please begin with the [frontend authorization guide](/docs/guides/javascript/auth/user-sessions). When your server receives a request, the location of the user's access token depends on whether your app uses local storage (the default) or cookies to manage user sessions: - If using **local storage** to store a user's session, the access token will be passed in the Authorization header of the request. - If using **cookies** to store a user's session, the access token will be passed in the openfort-token cookie on the request. For example, in [NextJS](https://nextjs.org/), you might extract the auth token from a `NextApiRequest` as follows: ```ts const accessToken = req.headers.authorization.replace('Bearer ', ''); ``` ```ts const accessToken = req.cookies['openfort-token']; ``` ## Verifying the user's access token Once you've obtained the user's access token from a request, you should verify the token against Openfort's verification key for your app to confirm that the token was issued by Openfort and the user referenced by the player Id in the token is truly authenticated. The access token is a standard ES256 JWT and the verification key is a standard Ed25519 public key. You can verify the access token against the public key using the [official supported libraries](/docs/libraries) library or using a third-party library for managing tokens. ### When using Openfort auth ```ts import Openfort from "@openfort/openfort-node"; const openfort = new Openfort(process.env.OPENFORT_SK); const authSession = openfort.iam.verifyAuthToken("USER_AUTH_TOKEN"); ``` ```csharp using Openfort.SDK.Model; class Program { static async Task Main() { var client = new Openfort.SDK.OpenfortClient("sk_test_..."); var authSession = await client.Iam.VerifyAuthToken("USER_AUTH_TOKEN"); } } ``` ### When using a third-party auth When using a third-party auth provider, you can either verify the token using the provider's SDK or use Openfort's SDK to verify the token. ```ts import Openfort from "@openfort/openfort-node"; const openfort = new Openfort(process.env.OPENFORT_SK); const authSession = openfort.iam.verifyOAuthToken({ provider: 'firebase', // one of "google" | "twitter" | "facebook" | "discord" | "epic_games" | "accelbyte" | "firebase" | "lootlocker" | "playfab" | "supabase" | "custom" | "oidc"; token: "USER_AUTH_TOKEN", tokenType: 'idToken', // either "idToken" | "customToken" }); ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/server/architecture.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'architecture', title: 'Architecture', description: 'Openfort design and architecture', } Openfort's smart contracts are [open source](https://github.com/openfort-xyz/openfort-contracts). Moreover, Openfort is buit on public goods infrastructure like the [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) or [ERC-6551](https://eips.ethereum.org/EIPS/eip-6551) standards. We choose open source tools which are scalable and make them simple to use. Openfort is not a 1-to-1 mapping of any wallet solution you've seen. While we offer many of the features that other solutions have, we go much further than anyone else because: (1) We're based on smart accounts not EOAs, and (2) we build the server stack so you don't have to worry about the reliability of the infrastructure. ## Architecture Openfort consists of modules that allow you to plug-and-play the tools to achieve your success. Our infrastructure orchestrates everything under the hood to make the development and maintenance easy. The 4 key components we take care of are: - **Smart accounts**: We offer optimized and diverse set of smart accounts to fit your needs. [Types of smart accounts](https://github.com/openfort-xyz/openfort-contracts). - **Embedded Signers**: Signers create non-custodial wallets for your users. [Embedded wallet](/docs/guides/wallets). - **Bundlers/RPCs**: We built a Meta Bundler Network to ensure reliable access to the blockchain. If one fails, another takes over. - **Paymasters**: We built the most customizable paymasters to configure granular rate limits and policies for gas sponsoring, through either our API or dashboard. - **Backend wallets**: These are externally-owned accounts to be used internally to manage the game flows and experience. They can execute game logic like escrow for competition or sending a minted asset to a player after winning a competition.
Openfort Architecture
Our goal at Openfort is to make _all_ of smart accounts easy to use and invisible to the player. That doesn't mean you can't enjoy all the benefits of it. If you're a game dev veteran, you'll probably be familiar with the integrations we offer. If you're a blockchain dev veteran it means you'll probably be able to use every inch of features and benefits we offer. In either scenario Openfort helps you build you weekend hackathon or your ambitious AAA game. ## Product Principles It is our goal to provide an architecture that any large-scale company would design for themselves, and then provide tooling around that architecture that is easy-to-use for indie-developers and small teams. We use a series of principles to ensure that scalability and usability are never mutually exclusive: ### Everything works in isolation Each system must work as a standalone tool with as few moving parts as possible. The litmus test for this is: "Can a user run this product with nothing but a Postgres database?" ### Everything is integrated Openfort is composable. Even though every product works in isolation, each product on the platform needs to 10x the other products. For integration, each tool should expose an API and Webhooks. ### Everything is extensible We're deliberate about adding a new tool, and prefer instead to extend an existing one. This is the opposite of many cloud providers whose product offering expands into niche use-cases. We provide _primitives_ for developers, which allow them to achieve any goal. Less, but better. ### Everything is portable To avoid lock-in, we make it easy to migrate in and out. Our cloud offering is compatible with our self-hosted product. We use existing standards to increase portability (like pg_dump and CSV files). If a new standard emerges which competes with a "Openfort" approach, we will deprecate the approach in favor of the standard. This forces us compete on experience. We aim to be the best Postgres hosting service. ### Build for developers "Developers" are a specific profile of user: they are _builders_. When assessing impact as a function of effort, developers have a large efficiency due to the type of products and systems they can build. As the profile of a developer changes over time, Openfort will continue to evolve the product to fit this evolving profile. export const Page = ({ children }) => export default Page --- File: /pages/guides/server/dev.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Backend wallets', breadcrumb: 'Server', } Backend wallets are externally-owned accounts that your application controls to manage on-chain operations. They act as trusted intermediaries that can handle various automated tasks and workflows in your application. As a developer, you can also use smart wallet as a backend wallet (some benefits include the batching of transactions), please refer to our guide on how to create [smart wallets](/docs/guides/javascript/smart-wallet/connected-wallets). ## Why use backend wallets? Backend wallets enable your application to: - Automate on-chain operations - Manage digital assets programmatically - Handle complex user interactions - Control asset distribution and collection ## How they work Backend wallets operate directly from your server, allowing you to programmatically execute transactions based on your application's logic. For example, in a gaming application, you could use a backend wallet to automatically distribute rewards when players complete challenges. Or in a marketplace application, you could use it to handle escrow during peer-to-peer trades. ## Key benefits - **Automation**: Execute transactions automatically based on your application's logic - **Security**: Control exactly how and when assets move through your application - **Flexibility**: Adapt to various use cases and business requirements - **Reliability**: Built for consistent performance and high availability ## Getting started To start using backend wallets in your application: 1. Create your wallet through the [Openfort dashboard](https://dashboard.openfort.xyz) 2. Set up policies to define transaction rules 3. Integrate the wallet into your application logic using our API export const Page = ({ children }) => export default Page --- File: /pages/guides/server/pregenerate-wallets.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' import { Accordion } from '@/components/ui' export const meta = { title: 'Pregenerating an embedded wallet', breadcrumb: 'Server', } You can pregenerate non-custodial wallet associated with a given account, like an email address or social login, without requiring the user to login. You can even send assets to the wallet before the user logs in to your app for the first time. Once the user associated with the account logs in, they will be able to access the pregenerated wallet and any assets sent to them. To pregenerate wallets, use one of the supported backend SDKs: A user can easily claim their pregenerated wallet simply by logging into your app with one of its linked accounts. ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const notifications = await openfort.iam.createAuthPlayer( { thirdPartyUserId: "user id", thirdPartyProvider: 'provider name', // Id of the provider of the user preGenerateEmbeddedAccount: true chainId: 4337, metadata: { name: "Jaume" } }, { shieldAuthProvider: '', // ShieldAuthProvider.OPENFORT or ShieldAuthProvider.CUSTOM apiKey: '', // Shield publishable key apiSecret: '', // Shield secret key encryptionPart: '' // Shield encryption share }) ``` ```csharp Program.cs using Openfort.SDK; using Openfort.SDK.Model; const openfort = new OpenfortClient(YOUR_SECRET_KEY); const notifications = await openfort.Iam.CreateAuthPlayer( new CreateAuthPlayerRequest( ThirdPartyUserId = "user id", ThirdPartyProvider = 'provider name', // Id of the provider of the user PreGenerateEmbeddedAccount = true, ChainId = 4337, ), new PreGenerateEmbeddedAccountsConfiguration( ShieldAuthProvider = ShieldAuthProvider.OPENFORT, // ShieldAuthProvider.OPENFORT or ShieldAuthProvider.CUSTOM ApiKey = '', // Shield publishable ApiSecret = '', // Shield secret key EncryptionPart = '' // Shield encryption share ) ); ``` In the body of the request: - `thirdPartyUserId`: the user's account id. - `thirdPartyProvider`: the provider used: custom, supabase, oidc, etc. - `preGenerateEmbeddedAccount`: boolean with the value **true**. A successful response will include the new user object along with their user's ID (`playerID`), like below: ```bash { "id": "pla_ff54b031-a878-4ca2-9cf5-ae190f921e9b", "object": "player", "createdAt": 1691658234, "linkedAccounts": [ { "provider": "email", "email": "jaume@openfort.xyz", "disabled": false, "updatedAt": 1691658234 } ] } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/server/setup.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' import { Accordion } from '@/components/ui' export const meta = { title: 'Setting up your server environment', breadcrumb: 'Server', } You can pregenerate wallets associated with a given account, like an email address or social login, without requiring the user to login. You can even send assets to the wallet before the user logs in to your app for the first time. Once the user associated with the account logs in, they will be able to access the pregenerated wallet and any assets sent to them. To pregenerate an embedded wallet, use one of the supported backend SDKs: ## Get your API keys To start, go to the [Openfort Dashboard](https://dashboard.openfort.xyz) and select your desired project from the dropdown at the top. Then, navigate to the Developers page > API Keys tab for your app. Then grab you secret key. Your app secret is a sensitive value that gives you permission to manage Openfort from your server. Do not expose it outside of your backend server. Once you've retrieved your API keys, you can begin interacting with Openfort's API in one of two ways: using the server-side SDKs, or querying Openfort's REST API directly. ## Server SDKs These libraries includes helpful utilities around verifying access tokens issued by Openfort and interacting with Openfort's API to query and import users, create wallets, verify webhooks, and more. You can visit the [SDK reference documentation](/docs/reference/api/introduction?lang=ts) to learn more about the available SDKs and how to use them in your server-side application. ```ts server.ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); ``` ```csharp Program.cs using Openfort.SDK; using Openfort.SDK.Model; const openfort = new OpenfortClient(YOUR_SECRET_KEY); ``` ## Using the REST API You can visit the [API reference documentation](/docs/reference/api/introduction) to learn more. For example, in a JavaScript fetch request, your headers should look like: ```js headers: { 'Authorization': `Bearer sk_test_...`, } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/server/usage.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { Accordion } from '@/components/ui' export const meta = { title: 'Using backend wallets', breadcrumb: 'Server', } ## Create wallet Backend wallets can be created through our dashboard or API. You can either create a new wallet or add an existing one. ### Using the Dashboard Navigate to the [Openfort dashboard](https://dashboard.openfort.xyz) and create a new developer account. ### Using the API You can create or add developer accounts through our API: ```ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const settings = await openfort.settings.createDeveloperAccount() ``` ```bash curl https://api.openfort.xyz/v1/settings/developer_accounts \ -u "$YOUR_SECRET_KEY:" \ -d address="0x..." \ -d signature="0x..." \ -d name="My Backend Wallet" ``` ## Transactions To execute a transaction from your backend wallet: ```ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const transactionintents = await openfort.transactionIntents.create({ account: 'dac_...', // Your backend wallet ID chainId: 80002, policy: 'pol_...', // Optional: Policy ID for gas sponsorship optimistic: true, interactions: { contract: 'con_....', functionName: 'transfer', functionArgs: ['recipient_address', 'amount'] } }) ``` ```bash curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d 'account=dac_...' \ -d optimistic=true \ -d 'interactions[0][contract]=con_....' \ -d 'interactions[0][functionName]=transfer' \ -d 'interactions[0][functionArgs][0]=recipient_address' \ -d 'interactions[0][functionArgs][1]=amount' ``` For gas sponsorship, make sure to set up appropriate policies with account_functions rules. Learn more about [creating policy sponsors](/docs/guides/platform/policies/overview). ### Checking transaction status You can monitor the status of transactions through our webhook system or by querying the API: ```ts const transactionIntent = await openfort.transactionIntents.retrieve('tin_...'); console.log(transactionIntent.status); ``` ```bash curl https://api.openfort.xyz/v1/transaction_intents/tin_... \ -u "$YOUR_SECRET_KEY:" ```
Minting NFTs with a backend wallet} id="minting" > In this example, we'll use a backend wallet to mint an NFT to a player's account: ```ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const transactionintents = await openfort.transactionIntents.create({ account: 'dac_...', // Your backend wallet ID chainId: 80002, policy: 'pol_...', // Policy for gas sponsorship optimistic: true, interactions: { contract: 'con_....', functionName: 'mint', functionArgs: ['pla_...'] // Player ID receiving the NFT } }) ``` ```bash curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d 'account=dac_...' \ -d optimistic=true \ -d 'interactions[0][contract]=con_....' \ -d 'interactions[0][functionName]=mint' \ -d 'interactions[0][functionArgs][0]=pla_...' ```
Transferring Assets} id="transferring" > Here's how to transfer assets from your backend wallet to another account: ```ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const transactionintents = await openfort.transactionIntents.create({ account: 'dac_...', // Your backend wallet ID chainId: 80002, policy: 'pol_...', // Policy for gas sponsorship optimistic: true, interactions: { contract: 'con_....', functionName: 'transfer', functionArgs: ['pla_...', '1000000000000000000'] // Player ID and amount (1 token) } }) ``` ```bash curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d 'account=dac_...' \ -d optimistic=true \ -d 'interactions[0][contract]=con_....' \ -d 'interactions[0][functionName]=transfer' \ -d 'interactions[0][functionArgs][0]=pla_...' \ -d 'interactions[0][functionArgs][1]=1000000000000000000' ```
Implementing Escrow System} id="escrow" > This example shows how to implement an escrow system using a backend wallet: 1. First, check the player's NFT inventory: ```ts const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const inventory = await openfort.inventories.getPlayerNftInventory({ player: 'pla_...', contract: 'con_...', }) ``` ```bash curl https://api.openfort.xyz/v1/accounts/acc_.../inventory/nft \ -u "$YOUR_SECRET_KEY:" \ -d 'contract=con_...' ``` 2. Then, transfer the asset to the escrow wallet: ```ts const transactionintents = await openfort.transactionIntents.create({ chainId: 80002, optimistic: false, player: 'pla_...', // Player ID policy: 'pol_...', // Policy for gas sponsorship interactions: { contract: 'con_...', functionName: "transferFrom", functionArgs: ['pla_...', 'dac_...', '10'], // From player to escrow wallet, token ID 10 } }); ``` ```bash curl https://api.openfort.xyz/v1/transaction_intents \ -u "$YOUR_SECRET_KEY:" \ -d chainId=80002 \ -d optimistic=false \ -d 'player=pla_...' \ -d 'policy=pol_...' \ -d 'interactions[0][contract]=con_...' \ -d 'interactions[0][functionName]=transferFrom' \ -d 'interactions[0][functionArgs][0]=pla_...' \ -d 'interactions[0][functionArgs][1]=dac_...' \ -d 'interactions[0][functionArgs][2]=10' ```
To keep your application in sync with blockchain events, Openfort provides [webhooks](/docs/guides/server/webhooks) for various events including transaction status changes and asset transfers. ## Signature Coming soon export const Page = ({ children }) => export default Page --- File: /pages/guides/server/webhooks.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'webhooks', title: 'Verifying a webhook payload', description: 'Listen for events on your Openfort account.', subtitle: 'Listen for events to automatically trigger reactions.', breadcrumb: 'Server', } Webhook payloads must be verified before they are trusted and used on your server. This is done by verifying a signature sent with your webhook. Your endpoint must return a 2xx (status code 200-299) response for the webhook to be marked as delivered. Any other statuses (including 3xx) are considered failed deliveries. ## Using `Openfort` SDK Use the Openfort SDK's `constructWebhookEvent` method to verify an incoming webhook. Pass in the request body and the signature header. As an example, you can verify a webhook using the code below: ```ts app.post( '/webhook', express.raw({ type: 'application/json' }), async (req: Request, _res: Response) => { const openfort = new Openfort('OPENFORT_SECRET_KEY') try { const event = await openfort.constructWebhookEvent( req.body.toString(), req.headers['openfort-signature'] ) switch (event.type) { case "transaction_intent.succeeded": console.log(`TransactionIntent ID: ${event.data.id}`) break case "transaction_intent.failed": console.log(`TransactionIntent ID: ${event.data.id}`) break default: console.log(`Unhandled event type ${event.type}`); } } catch (e) { console.error((e as Error).message) } } ) ``` ```csharp [HttpPost("webhook")] public async Task Webhook() { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); WebHookEvent openfortEvent; try { openfortEvent = client.ConstructWebhookEvent( json, Request.Headers["openfort-signature"] ); // Handle the webhook event var type = openfortEvent.Type; var transactionIntent = openfortEvent.Data; Console.WriteLine($"Webhook notification: {openfortEvent} found"); } catch (Exception e) { Console.WriteLine($"Something failed {e}"); return BadRequest(); } var transactionIntent = openfortEvent.Data; Console.WriteLine($"TransactionIntent ID: {transactionIntent.Id}"); return Ok(); } ``` ## Webhook object The webhook object contains the following fields: ```json { "data": { "id": "tin_c502d628-5bb3-42f2-b8f5-62ba4d71df3a", "createdAt": 1689869074, "object": "transactionIntent", "etc":"..." }, "type": "transaction_intent.succeeded", "date": 1689869074 } ``` Where the `type` will be one of the following: - `transaction_intent.succeeded`: The transaction intent has arrived on-chain and is confirmed. - `transaction_intent.failed`: The transaction intent has arrived on-chain and is reverted. - `transaction_intent.cancelled`: The transaction intent parameters were not met. - `transaction_intent.broadcast`: The transaction intent was broadcasted. - `balance. project`: The project balance. - `balance.contract`: The contract balance. - `balance.dev_account`: The balance of your backend wallet. The `data` will be a [transaction intent object](https://www.openfort.xyz/docs/reference/api/get-a-transaction-intent-object).
{'Use your dashboard to register webhooks.'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/email.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Email and Password', description: 'Allow users to sign in with a password connected to their email ', breadcrumb: 'Authentication', } Allow users to sign in with a password connected to their email address in your Unity game. You can update the server sending email notifications and the email templates through your dashboard. Visit the guide on how to [update password authentication](/docs/guides/dashboard/password/custom-smtp) to learn more. ## Setting up authentication First, create a manager class to handle Openfort authentication: ```csharp using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class OpenfortAuthManager : MonoBehaviour { private OpenfortSDK openfort; private async void Start() { if (OpenfortSDK.Instance != null) { openfort = OpenfortSDK.Instance; } openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); } } ``` ## Sign up a new user To register a new user with email and password: ```csharp public class OpenfortAuthManager : MonoBehaviour { // ... previous code ... public async Task SignUpNewUser(string email, string password) { try { await openfort.SignUpWithEmailPassword(email, password); Debug.Log("User signed up successfully"); } catch (Exception e) { Debug.LogError($"Error signing up user: {e.Message}"); } } // Optional: Send email verification public async Task RequestEmailVerification(string email) { try { await openfort.RequestEmailVerification(email); Debug.Log("Verification email sent"); } catch (Exception e) { Debug.LogError($"Error sending verification email: {e.Message}"); } } } ``` ## Log in a user To authenticate an existing user: ```csharp public class OpenfortAuthManager : MonoBehaviour { // ... previous code ... public async Task LogInUser(string email, string password) { try { var response = await openfort.LogInWithEmailPassword(email, password); Debug.Log("User logged in successfully"); // The response contains: // - response.player: Player information // - response.token: Authentication token // - response.refreshToken: Token for refreshing authentication // Store these tokens as needed for your game } catch (Exception e) { Debug.LogError($"Error logging in: {e.Message}"); } } } ``` ### Authentication response Upon successful authentication, you'll receive a response containing: ```json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "email", "disabled": false, "verified": true, "email": "hello@example.com" } ] }, "token": "eyJhbGci...", "refreshToken": "eyJhbGci..." } ``` ## Log out To log out a user: ```csharp await openfort.Logout(); ``` ## Password reset flow For implementing a password reset flow in your Unity game: ```csharp public class OpenfortAuthManager : MonoBehaviour { // ... previous code ... public async Task RequestPasswordReset(string email) { try { await openfort.RequestResetPassword(email); Debug.Log("Password reset email sent"); } catch (Exception e) { Debug.LogError($"Error requesting password reset: {e.Message}"); } } public async Task ResetPassword(string email, string newPassword, string verificationState) { try { await openfort.ResetPassword(email, newPassword, verificationState); Debug.Log("Password reset successfully"); } catch (Exception e) { Debug.LogError($"Error resetting password: {e.Message}"); } } } ``` ## UI integration example Here's a basic example of how to integrate this with Unity UI: ```csharp public class AuthUIManager : MonoBehaviour { [SerializeField] private TMP_InputField emailInput; [SerializeField] private TMP_InputField passwordInput; [SerializeField] private Button signUpButton; [SerializeField] private Button loginButton; private OpenfortAuthManager authManager; private void Start() { authManager = GetComponent(); signUpButton.onClick.AddListener(HandleSignUp); loginButton.onClick.AddListener(HandleLogin); } private async void HandleSignUp() { await authManager.SignUpNewUser(emailInput.text, passwordInput.text); } private async void HandleLogin() { await authManager.LogInUser(emailInput.text, passwordInput.text); } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/external-wallet.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'External Wallet Authentication ', description: 'Authenticate users with external wallets', subtitle: 'Learn how to connect the external wallets to authenticate users.', breadcrumb: 'Authentication', } Connect wallets via the [Sign in With Ethereum (SIWE)](https://eips.ethereum.org/EIPS/eip-4361) standard. This authentication method is designed for users who prefer to authenticate using their external wallets. Openfort's Unity integration facilitates a secure and direct authentication process using these wallets. ## Setting up wallet authentication First, create a manager class to handle Openfort wallet authentication: ```csharp using UnityEngine; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class OpenfortWalletManager : MonoBehaviour { private OpenfortSDK openfort; private async void Start() { openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); } } ``` ## Initialize SIWE authentication To start the SIWE (Sign in With Ethereum) process: ```csharp public class OpenfortWalletManager : MonoBehaviour { // ... previous code ... public async Task InitializeSIWE(string walletAddress) { try { await openfort.InitSIWE(new InitSiweRequest(walletAddress)); Debug.Log("SIWE initialization successful"); } catch (Exception e) { Debug.LogError($"Error initializing SIWE: {e.Message}"); } } } ``` ## Verify SIWE signature After getting the signature from the wallet, verify it to authenticate the user: ```csharp public class OpenfortWalletManager : MonoBehaviour { // ... previous code ... public async Task AuthenticateWithSIWE( string signature, string message, string walletClientType, // e.g., "metamask", "coinbaseWallet" string connectorType) // e.g., "wallet_connect_v2", "injected", "coinbase_wallet" { try { var request = new AuthenticateWithSiweRequest( signature, message, walletClientType, connectorType ); var response = await openfort.AuthenticateWithSIWE(request); Debug.Log("SIWE authentication successful"); // The response contains: // - response.player: Player information // - response.token: Authentication token // - response.refreshToken: Token for refreshing authentication // Store these tokens as needed for your game } catch (Exception e) { Debug.LogError($"Error authenticating with SIWE: {e.Message}"); } } } ``` ### Authentication response Upon successful authentication, you'll receive a response containing: ```json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "wallet", "address": "0x1234567890abcdef", "disabled": false, } ] }, "token": "eyJhbGci...", "refreshToken": "eyJhbGci..." } ``` ## UI integration example Here's a basic example of how to integrate wallet authentication with Unity UI: ```csharp public class WalletAuthUI : MonoBehaviour { [SerializeField] private Button connectWalletButton; [SerializeField] private TMP_Text statusText; private OpenfortWalletManager walletManager; private string userWalletAddress; private void Start() { walletManager = GetComponent(); connectWalletButton.onClick.AddListener(HandleWalletConnection); } private async void HandleWalletConnection() { statusText.text = "Connecting wallet..."; try { // First initialize SIWE await walletManager.InitializeSIWE(userWalletAddress); // After getting signature from wallet (implementation depends on your wallet integration) string signature = await GetWalletSignature(); string message = await GetSIWEMessage(); // Authenticate await walletManager.AuthenticateWithSIWE( signature, message, "metamask", // or your chosen wallet "injected" // or your chosen connector type ); statusText.text = "Wallet connected!"; } catch (Exception e) { statusText.text = "Connection failed: " + e.Message; } } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/guest.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Guest Mode', description: 'Enable users to quickly start using your application without registration', subtitle: 'Learn how to implement guest authentication in your application', breadcrumb: 'Authentication', } User data and embedded wallets from guest sessions cannot be merged into an existing user account — guest accounts can only be upgraded into a new user account. If a guest user wants to log in with an existing account, you must delete the guest user session first. Use the `OnSignUpGuest` method from the Openfort SDK to create a guest account: ```csharp public async void OnSignUpGuest() { loadingPanel.SetActive(true); registerButton.interactable = false; statusTextLabel.text = $"Logging In As Guest ..."; try { AuthResponse authResponse = await openfort.SignUpGuest(); accessToken = authResponse.Token; await SetAutomaticRecoveryMethod(); loginPanel.SetActive(false); statusTextLabel.text = $"Logged In As Guest"; loggedinPanel.SetActive(true); } catch (System.Exception) { loginPanel.SetActive(false); registerPanel.SetActive(true); } signinButton.interactable = true; loadingPanel.SetActive(false); } ``` Upon successful registration, you'll receive a response containing the player information and authentication tokens: ```json { "player": { "id": "pla_...", "object": "player", "createdAt": 1234567890, "linkedAccounts": [] }, "token": "eyJhbG...", "refreshToken": "eyJhbG..." } ``` ### Upgrade a guest user to a logged-in user Simply call [link method](/docs/guides/auth/user-management/linking) to enable the guest user to upgrade their account to a logged-in account using any authentication method of their choice. export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/oauth.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Social Login (OAuth)', breadcrumb: 'Authentication', } Create a script with the following code and bind it to an object. The SDK exports a method called `AuthenticateWithOAuth` that implements the pooling OAuth flow. The method takes an `OAuthInitRequest` object as a parameter. The object contains the provider, the redirect URL, and the pooling option. ```csharp using System.Collections; using System.Collections.Generic; using UnityEngine; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class InitOpenfort : MonoBehaviour { private OpenfortSDK openfort; async void Start() { string publishableKey = "YOUR_OPENFORT_PUBLISHABLE_KEY"; openfort = await OpenfortSDK.Init(publishableKey); } public async void OnGoogleClicked() { OAuthInitRequest request = new OAuthInitRequest() { Provider = OAuthProvider.FACEBOOK, UsePooling = false, Options = new OAuthInitRequestOptions() { RedirectTo = "mygame://callback" }, }; await openfort.AuthenticateWithOAuth(request); } } ``` Openfort is now accessible from anywhere via Openfort.Instance. Standalone Windows applications do not support window deep linking from a web browser to the application. Modify the request above to: ```csharp OAuthInitRequest request = new OAuthInitRequest() { Provider = OAuthProvider.FACEBOOK, }; ``` ## Android, iOS and macOS ### Android setup On Android, we utilize [Chrome Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs/) (if available) to seamlessly connect gamers to Passport from within the game. **UNITY VERSIONS BELOW 2021.3** To check if Chrome Custom Tabs are available, older Unity versions may require a specific Gradle plugin version. For example, on Unity 2019.4, you must upgrade from 3.4.* to 3.4.3 (see Android's blog post): 1. In Unity go to Build Settings -> Player Settings -> Android -> Publishing Settings -> Enable Custom Base Gradle Template under the Build section 2. Open the newly generated Assets/Plugins/Android/baseProjectTemplate.grade file 3. Update classpath `com.android.tools.build:gradle:3.4.0` to classpath `com.android.tools.build:gradle:3.4.3` 1. In Unity go to **Build Settings** -> **Player Settings** -> **Android** -> **Publishing Settings** -> Enable **Custom Main Manifest** and **Custom Main Gradle Template** under the **Build** section 2. Open the newly generated `Assets/Plugins/Android/AndroidManifest.xml` file. Add the following code inside the `` element: ``` xml ``` 3. Open the newly generated `Assets/Plugins/Android/mainTemplate.gradle` file. Add the following code inside `dependencies` block: For this version of the Chrome Custom Tabs to work, the compileSdkVersion must be at least 33. This is usually the same value as the targetSdkVersion, which you can set in **Build Settings** -> **Player Settings** -> **Android** -> **Other Settings** -> **Target API Level**. **Proguard** If you enable **Minify** in your project settings, you will need to add a custom Proguard file to your project. 1. In Unity go to **Build Settings** -> **Player Settings** -> **Android** -> **Publishing Settings** -> Enable **Custom Proguard File** under the **Build** section 2. Open the newly generated Assets/Plugins/Android/proguard-user.txt file. Add the following code inside the `` element ``` txt -dontwarn com.openfort.** -keep class com.openfort.** { *; } -keep interface com.openfort.** { *; } -dontwarn androidx.** -keep class androidx.** { *; } -keep interface androidx.** { *; } ``` The application will now open when the device processes any link that starts with `mygame://callback`. ### iOS setup 1. In Unity go to **Build Settings** -> **Player Settings** -> **iOS** -> **Other Settings** -> **Supported URL schemes**. 2. Increment the **Size** number. 3. Add your URL scheme in the **Element** field, e.g. if the deeplink URL is `mygame://callback`, add the scheme `mygame` to the field. Uppon successful authentication, the SDK will return a token that can be used to authenticate the user in your application. ```json response.json { "player": { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "facebook", "disabled": false, "externalUserId": "2" } ] }, "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJhdWQiOiJwcm9fOGY3ZTM1NTktMjhkNy00MWE2LTgxNGMtMjU0OTkzZTdkNjFkLXRlc3QiLCJleHAiOjE3MTA5ODI2MDIsImlhdCI6MTcxMDk3OTAwMiwiaXNzIjoib3BlbmZvcnQueHl6Iiwic2lkIjoiMzhhMDdmMzktMTUxOS00MjE0LWJmNmMtNzI0Zjg0ZDBiZGQwIiwic3ViIjoicGxhX2NjOWVkMmI3LWM1ZjUtNGM0My04ZGNhLWM0YjEwNGJhMTc2MiJ9.EcFtS__GwyxJu1S3tO7jMBbTCIJCpqsoNxxJrqILrKjNl2N5-SIMG2z_s2Vs8ztG6KAVy6zIp6P9GzfD7s4JiA", "refreshToken": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImNmODNlMTM1N2VlZmI4YmRmMTU0Mjg1MGQ2NmQ4MDA3ZDYyMGU0MDUwYjU3MTVkYzgzZjRhOTIxZDM2Y2U5Y2U0N2QwZDEzYzVkODVmMmIwZmY4MzE4ZDI4NzdlZWMyZjYzYjkzMWJkNDc0MTdhODFhNTM4MzI3YWY5MjdkYTNlIn0.eyJzaWQiOiIzOGEwN2YzOS0xNTE5LTQyMTQtYmY2Yy03MjRmODRkMGJkZDAiLCJpYXQiOjE3MTA5NzkwMDIsImV4cCI6MTcxMzU3MTAwMn0.koNd4eoevBQQR3-z0CMGL5qVzOURZEeAgjvrHMRloLgDbScS2Qbi4W-vf2fE0fYOWUIAHnAq7cDABNwSQrEvSQ" } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/third-party.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Third-party authentication', description: 'Integrate with existing auth providers and backends', subtitle: 'Learn how to integrate with third-party auth provider.', breadcrumb: 'Authentication', } Openfort's embedded signers are fully compatible with any authentication provider that supports JWT-based, stateless authentication. This guide will show you how to integrate third-party authentication providers in your Unity game. Follow the guide on how to [configure third party auth](/docs/guides/dashboard/external-auth) to learn more. The supported loginMethods are `'accelbyte'`, `'custom'`, `'firebase'`, `'supabase'`, `'lootlocker'`, `'playfab'`, `'telegramMiniApp'` and `'oidc'`. ## Basic Setup First, create a manager class to handle Openfort authentication: ```csharp using UnityEngine; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class OpenfortAuthManager : MonoBehaviour { private OpenfortSDK openfort; private async void Start() { openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); } } ``` ## Authenticate with third-party provider Here's how to authenticate using a third-party provider: To make these instructions concrete, this guide uses [Firebase](https://firebase.com) as a sample third party auth provider that you can integrate alongside Openfort. ```csharp public class OpenfortAuthManager : MonoBehaviour { // ... previous code ... public async Task AuthenticateWithProvider(string token) { try { var request = new ThirdPartyProviderRequest( ThirdPartyOAuthProvider.Firebase, // Or other provider token, TokenType.IdToken // Or TokenType.CustomToken ); var response = await openfort.AuthenticateWithThirdPartyProvider(request); Debug.Log("Third-party authentication successful"); // Handle successful authentication HandleAuthenticationSuccess(response); } catch (Exception e) { Debug.LogError($"Authentication error: {e.Message}"); } } private void HandleAuthenticationSuccess(PlayerResponse response) { // response.id contains the player ID // response.linkedAccounts contains the linked provider accounts Debug.Log($"Authenticated player ID: {response.Id}"); } } ``` ### Authentication response Upon successful authentication, you'll receive a response containing: ```json { "id": "pla_cc9ed2b7-c5f5-4c43-8dca-c4b104ba1762", "object": "player", "createdAt": 1710976453, "linkedAccounts": [ { "provider": "firebase", "disabled": false, "externalUserId": "2" } ] } ``` ## Example
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'Firebase Auth w/ Unity Android', description: 'An integration with Google Play Games using Firebase Auth as a third party auth provider.', href: 'https://github.com/openfort-xyz/sample-unity-firebaseauth-embedded-signer' } ] export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/auth/user-sessions.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'User Session Management', description: 'Using Openfort Auth to onboard new users.', subtitle: 'Understand how to onboard with the Openfort signer solution.', breadcrumb: 'Authentication', } Here's a complete example of managing sessions in Unity: ```csharp using UnityEngine; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class SessionManager : MonoBehaviour { private OpenfortSDK openfort; private async void Start() { openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); } // Get the current access token public async Task GetAccessToken() { try { string accessToken = await openfort.GetAccessToken(); return accessToken; } catch (Exception e) { Debug.LogError($"Error getting access token: {e.Message}"); return null; } } // Using the access token for API requests public async Task MakeAuthenticatedRequest(string endpoint) { try { string accessToken = await GetAccessToken(); // Example using UnityWebRequest using (UnityWebRequest request = UnityWebRequest.Get(endpoint)) { request.SetRequestHeader("Authorization", $"Bearer {accessToken}"); await request.SendWebRequest(); if (request.result == UnityWebRequest.Result.Success) { string response = request.downloadHandler.text; // Handle response } } } catch (Exception e) { Debug.LogError($"API request failed: {e.Message}"); } } // Logout functionality public async Task LogoutUser() { try { await openfort.Logout(); Debug.Log("User logged out successfully"); // Additional cleanup if needed // For example, return to login screen SceneManager.LoadScene("LoginScene"); } catch (Exception e) { Debug.LogError($"Logout error: {e.Message}"); } } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/embedded-signer/recovery.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Create and recover signers', description: 'Create and manage embedded wallets for your users', subtitle: 'Create and manage embedded wallets for your users', breadcrumb: 'Embedded wallets', } ## Understanding embedded signers To create wallets for your users during the login flow, you need to configure the embedded signer. The configuration depends on your chosen recovery method, so it's important to decide on your recovery strategy first. Always wait for the embedded state to be ready before using the embedded signer. See the [integration guide](/docs/guides/unity/embedded-signer/state). ## Choosing a Recovery Method There are two core recovery modes for Openfort embedded signers: - [Automatic Recovery](/docs/guides/unity/embedded-signer/recovery###Automatic-recovery-setup): Recovery share is encrypted using project and Openfort entropy - [User-based Recovery](/docs/guides/unity/embedded-signer/recovery###User-based-recovery-setup): Recovery share is encrypted using user-provided entropy (password) ### Automatic recovery setup Automatic recovery provides smooth UX but requires careful security considerations. You can implement it using either Openfort Auth or a third-party authentication provider: When using automatic recovery, **Shield** generates a password that is used for the encryption of the recovery share. The full encryption key can only be accessed if the decryption request includes the user's auth token. When using **automatic recovery**, its very important to ensure that the `encryption share` should not be available from the client side of the application. **From your backend**, you should have an endpoint that generates an encryption session for the user. This endpoint should be protected and only accessible by the user who is requesting the encryption session (i.e. the user who is logging in). An encryption session is requested every time `configureEmbeddedSigner` is called. The encryption session is only valid for **a single use**. For example, in a Next.js API route, you can create an endpoint like this: ```ts protected-create-encryption-session.ts import openfort from './openfortAdminConfig'; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const session = await openfort.registerRecoverySession('YOUR_SHIELD_PUBLISHABLE_KEY', 'YOUR_SHIELD_SECRET_KEY', 'YOUR_SHIELD_ENCRYPTION_SHARE') res.status(200).send({ session: session, }); } ``` ```ts openfortAdminConfig.ts import Openfort from '@openfort/openfort-node'; const openfort = new Openfort('YOUR_OPENFORT_SECRET_KEY'); export default openfort; ``` Once we've secured the backend we setup the client side: ```csharp openfortManager.cs using System; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; using static Clients.Shield; public class EmbeddedSignerManager : MonoBehaviour { private OpenfortSDK openfort; // Setup with Openfort authentication public async Task SetupAutomaticRecoveryWithOpenfort(string email, string password) { try { // Sign up the user AuthResponse response = await openfort.SignUpWithEmailPassword(email, password); string token = response.Token; // Get encryption session from your backend string encryptionSession = await GetEncryptionSession(); // Configure the signer int chainId = 80002; // Polygon Amoy testnet ShieldAuthentication shieldConfig = new ShieldAuthentication( ShieldAuthType.Openfort, token ) { EncryptionSession = encryptionSession }; EmbeddedSignerRequest request = new EmbeddedSignerRequest(chainId, shieldConfig); await openfort.ConfigureEmbeddedSigner(request); Debug.Log("Automatic recovery setup complete"); } catch (Exception e) { Debug.LogError($"Error setting up automatic recovery: {e.Message}"); } } } ``` ```csharp encryptionSession.cs using System; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; public class EncryptionSessionManager { public static async Task GetEncryptionSession() { string url = "https://your-api-endpoint.com/api/protected-create-encryption-session"; using (UnityWebRequest webRequest = UnityWebRequest.Post(url, "{}")) { webRequest.SetRequestHeader("Content-Type", "application/json"); var operation = webRequest.SendWebRequest(); while (!operation.isDone) await Task.Yield(); if (webRequest.result != UnityWebRequest.Result.Success) { Debug.LogError($"Failed to create encryption session: {webRequest.error}"); throw new Exception("Failed to create encryption session"); } string jsonResponse = webRequest.downloadHandler.text; SessionResponse response = JsonUtility.FromJson(jsonResponse); return response.session; } } } [Serializable] public class SessionResponse { public string session; } ``` This example will showcase **Firebase** as the third-party auth provider. You can replace it with any other [third-party auth provider](/docs/guides/unity/auth/external-auth). ```csharp openfortManager.cs using System; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; using static Clients.Shield; public async Task SetupAutomaticRecoveryWithThirdParty(string idToken) { try { // Authenticate with third-party provider await openfort.AuthenticateWithThirdPartyProvider( new ThirdPartyProviderRequest( ThirdPartyOAuthProvider.Firebase, idToken, TokenType.IdToken ) ); // Get encryption session from your backend string encryptionSession = await GetEncryptionSession(); // Configure the signer int chainId = 80002; ShieldAuthentication shieldConfig = new ShieldAuthentication( ShieldAuthType.Openfort, idToken, "firebase", "idToken" ) { EncryptionSession = encryptionSession }; EmbeddedSignerRequest request = new EmbeddedSignerRequest(chainId, shieldConfig); await openfort.ConfigureEmbeddedSigner(request); Debug.Log("Third-party automatic recovery setup complete"); } catch (Exception e) { Debug.LogError($"Error setting up third-party automatic recovery: {e.Message}"); } } ``` ```csharp encryptionSession.cs using System; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Networking; public class EncryptionSessionManager { public static async Task GetEncryptionSession() { string url = "https://your-api-endpoint.com/api/protected-create-encryption-session"; using (UnityWebRequest webRequest = UnityWebRequest.Post(url, "{}")) { webRequest.SetRequestHeader("Content-Type", "application/json"); var operation = webRequest.SendWebRequest(); while (!operation.isDone) await Task.Yield(); if (webRequest.result != UnityWebRequest.Result.Success) { Debug.LogError($"Failed to create encryption session: {webRequest.error}"); throw new Exception("Failed to create encryption session"); } string jsonResponse = webRequest.downloadHandler.text; SessionResponse response = JsonUtility.FromJson(jsonResponse); return response.session; } } } [Serializable] public class SessionResponse { public string session; } ``` We recommend enabling user-based recovery for users. This is especially important to enforce as the value of assets in a user's wallet grows. --- ### User-based recovery setup **Password recovery** Require that users set a password when the wallet is created, enforcing password-based recovery from the start. If encrypted by user-provided entropy, **only the user can decrypt the recovery share**. Openfort never sees or the user's password. Therefore, if you're not planning to ever user the automatic recovery mode, you can use the `encryption share` in the client side of the application. ```csharp using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class openfortManager: MonoBehaviour { private OpenfortSDK Openfort; private async void AuthAndSetPassordRecoveryMethod(string email, string password, string recoveryPassword) { AuthResponse response = await Openfort.SignUpWithEmailPassword(email, password); string token = response.Token; int chainId = 80002; ShieldAuthentication shieldConfig = new ShieldAuthentication(ShieldAuthType.Openfort, token); EmbeddedSignerRequest request = new EmbeddedSignerRequest(chainId, shieldConfig, recoveryPassword); await Openfort.ConfigureEmbeddedSigner(request); } } ``` This example will showcase **Firebase** as the third-party auth provider. You can replace it with any other third-party auth provider [supported by Openfort](/docs/guides/auth/external-auth) or with [Custom Auth](/docs/guides/auth/custom-auth). ```csharp using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class openfortManager: MonoBehaviour { private OpenfortSDK Openfort; private async void AuthAndSetPassordRecoveryMethod(string token, string recoveryPassword) { await Openfort.AuthenticateWithThirdPartyProvider(new ThirdPartyProviderRequest(ThirdPartyOAuthProvider.Firebase, token, TokenType.IdToken)); int chainId = 80002; ShieldAuthentication shieldConfig = new ShieldAuthentication(ShieldAuthType.Openfort, token, "firebase", "idToken"); EmbeddedSignerRequest request = new EmbeddedSignerRequest(chainId, shieldConfig, recoveryPassword); await Openfort.ConfigureEmbeddedSigner(request); } } ``` --- ## Pregeneration Openfort also allows you to pregenerate embedded wallets for your users, even before they first login to your game. Please see our [pregeneration guide](/docs/guides/server/pregenerate-wallets) for more. export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/embedded-signer/sign-messages.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Sign messages with the embedded signer ', subtitle: 'Learn how to sign messages and typed data using the embedded signer in Unity', breadcrumb: 'Wallets', } ## Prerequisites Before implementing message signing: - Ensure Openfort's `embeddedState` is `ready` - Verify the user is properly authenticated - Have an embedded signer configured ## Message Signing To request a signature from a user, use the `SignMessage` method. This implements the EIP-191 [personal_sign](https://docs.metamask.io/wallet/reference/personal_sign/) standard. ```csharp using UnityEngine; using System; using System.Threading.Tasks; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class MessageSigningManager : MonoBehaviour { private OpenfortSDK openfort; public async Task SignBasicMessage(string message) { try { var signMessageRequest = new SignMessageRequest(message); var signature = await openfort.SignMessage(signMessageRequest); Debug.Log($"Message signed successfully. Signature: {signature}"); return signature; } catch (Exception e) { Debug.LogError($"Error signing message: {e.Message}"); throw; } } } ``` ## Typed Data Signing For signing EIP-712 typed data, use the `SignTypedData` method. This implements the [eth_signTypedData_v4](https://docs.metamask.io/wallet/reference/eth_signtypeddata_v4/) standard. ```csharp public class MessageSigningManager : MonoBehaviour { // ... previous code ... public async Task SignTypedData( Dictionary domain, Dictionary types, Dictionary value) { try { var request = new SignTypedDataRequest(domain, types, value); var signature = await openfort.SignTypedData(request); Debug.Log($"Typed data signed successfully. Signature: {signature}"); return signature; } catch (Exception e) { Debug.LogError($"Error signing typed data: {e.Message}"); throw; } } } ``` ### Example of Typed Data Structure ```csharp // Example of structured data for signing public void CreateAndSignTypedData() { var domain = new Dictionary { { "name", "My Game" }, { "version", "1" }, { "chainId", 1 }, { "verifyingContract", "0x1234567890123456789012345678901234567890" } }; var types = new Dictionary { { "Person", new[] { new { name = "name", type = "string" }, new { name = "score", type = "uint256" } } } }; var value = new Dictionary { { "name", "Alice" }, { "score", 100 } }; SignTypedData(domain, types, value); } ``` ## Examples
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'Unity Sample Android Embedded Signer', description: 'An integration with Google Play Games using Firebase Auth as a third party auth provider to create a non-custodial embedded signer.', href: 'https://github.com/openfort-xyz/sample-unity-firebaseauth-embedded-signer', }, { name: 'Unity Sample WebGL Embedded Signer', description: 'An integration with Openfort Auth with non-custodial embedded signer.', href: 'https://github.com/openfort-xyz/sample-unity-webgl-embedded-signer', } ] export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/embedded-signer/state.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Create and recover signers', description: 'Get embedded state', subtitle: 'Learn how to configure and use embedded wallets in your Unity game', breadcrumb: 'Embedded wallets', } There are **two** essential steps to configure Openfort's embedded wallets in your Unity application: 1. Configure the embedded signer 2. Wait for the embedded signer to be ready ## Embedded Signer Configuration The Openfort SDK provides methods to configure a non-custodial embedded signer for blockchain interactions and transaction signing in your Unity game. Here's how to implement the configuration: ```csharp using UnityEngine; using System; using System.Threading.Tasks; using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class OpenfortManager : MonoBehaviour { private OpenfortSDK openfort; private async void Start() { try { openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); } catch (Exception e) { Debug.LogError($"Initialization error: {e.Message}"); } } public async Task ConfigureEmbeddedWallet(string authToken, string password = null) { try { int chainId = 80002; // Polygon Amoy testnet // Create shield authentication configuration var shieldAuth = new ShieldAuthentication( ShieldAuthType.Openfort, // or ShieldAuthType.Custom for third-party auth authToken ); // Create the embedded signer request var request = new EmbeddedSignerRequest( chainId, shieldAuth, password // Optional: for user-based recovery ); // Configure the embedded signer await openfort.ConfigureEmbeddedSigner(request); Debug.Log("Embedded signer configured successfully"); } catch (Exception e) { Debug.LogError($"Configuration error: {e.Message}"); throw; } } } ``` ### Configuration Parameters The `EmbeddedSignerRequest` takes the following parameters: | Parameter | Description | |-----------|-------------| | chainId | The blockchain network identifier. See [supported chains](/docs/chains) | | shieldAuth | Authentication configuration including auth type and token | | password | Optional: Recovery password for user-based recovery | The `ShieldAuthentication` configuration includes: | Parameter | Description | |-----------|-------------| | auth | Either `ShieldAuthType.Openfort` or `ShieldAuthType.Custom` | | token | The access or ID token for user verification | ## Checking Embedded Signer State The embedded signer goes through several states during initialization. It's crucial to wait for the proper state before using the signer. ### Embedded States | State | Value | Description | |-------|-------|-------------| | NONE | 0 | Initial SDK state | | UNAUTHENTICATED | 1 | Before user authentication | | EMBEDDED_SIGNER_NOT_CONFIGURED | 2 | Before signer configuration | | CREATING_ACCOUNT | 3 | Creating new account for chainID | | READY | 4 | Signer ready for use | Here's how to check the embedded signer state: ```csharp public class OpenfortManager : MonoBehaviour { private OpenfortSDK openfort; public async UniTask GetEmbeddedState() { return await GetOpenfortImpl().GetEmbeddedState(); } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/backend/firebase-extension.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Integrate Firebase with Openfort in Unity', description: 'Learn how you can create your game in Firebase with a blockchain integration with Openfort.', subtitle: 'Learn how to integrate Firebase backend and Openfort with your game', tocVideo: '3DOZhuqKdG0', } ## Overview [Firebase](https://firebase.google.com/) is Google's all-encompassing app development platform, providing game developers with an array of backend tools powered by Google Cloud. Within Unity, we've integrated the Firebase SDK to facilitate backend functionalities. Coupled with the [Google Play Games plugin for Unity](https://github.com/playgameservices/play-games-plugin-for-unity), it ensures a secure and efficient login for Android users. The integration is further enhanced with the [Openfort Firebase extension](https://extensions.dev/extensions/openfort/firestore-openfort-transactions), which incorporates the [Openfort SDK](https://github.com/openfort-xyz/openfort-node). This enables Unity clients to directly leverage Openfort's blockchain capabilities, allowing for sophisticated blockchain interactions within the gaming environment. ## Application Workflow
Integration workflow
## Prerequisites - Sign in to [dashboard.openfort.xyz](http://dashboard.openfort.xyz) and create a new project. - You need a [Google Play Developer account](https://support.google.com/googleplay/android-developer/answer/6112435?hl=en). - You need a [Google Cloud project](https://developers.google.com/workspace/guides/create-project). - Clone or download the repository and open it with Unity [2021.3](https://unity.com/releases/editor/qa/lts-releases?version=2021.3). When opening the project, select ***Ignore*** on this popup:
ignore popup
Once opened, you will see some reference errors. We will solve this in the next step by importing the Firebase SDK. - Follow the [Firebase-Unity setup guide](https://firebase.google.com/docs/unity/setup?hl=es-419). On [step 4](https://firebase.google.com/docs/unity/setup?hl=es-419#add-sdks), you just need to import ***FirebaseAuth*** and ***FirebaseFirestore*** packages:
import Firebase packages
Do it one by one and disable ***ExternalDependencyManager*** folder before importing:
import unity package
Most reference errors should be solved by now. If `UnityEditor.iOS.Extensions.Xcode` error is still standing, select ***Firebase.Editor*** asset, disable ***Validate References*** and choose ***Apply***:
resolve packages
- Create a keystore Follow this [guide](https://docs.unity3d.com/Manual/android-keystore-create.html) to create a new keystore for the Unity project. - Find SHA1 certificate fingerprint You need to extract the certificate fingerprint from the created keystore. Follow this [video tutorial](https://www.youtube.com/watch?v=lDXE4lfM0aQ) on how to do it, it also covers the creation of the keystore. This is the command that you will need to run: ```shell keytool -list -v -keystore "path/to/your/keystore" -alias "your_key_alias" ``` ## Set up Firebase ### Add Google sign-in provider Go to the [Firebase console](https://console.firebase.google.com/?hl=es-419), select your project and select ***Authentication***:
setup authentication firebase
After selecting ***Get started***, select ***Google*** as a sign-in provider:
choose the auth method
Activate ***Enable*** toggle, choose a public-facing name and select ***Save***:
setup google
A popup will appear. Copy the ***Web client ID*** and the ***Web client secret*** somewhere safe and choose ***Done***. You will see your Google provider enabled:
enabled google
Select the provider and choose ***Project Settings***. Under ***Your apps*** section select ***Add fingerprint*** and add your [SHA1 certificate fingerprint](https://github.com/openfort-xyz/firebase-extension-unity-sample/tree/main#find-sha1-certificate-fingerprint). Then choose ***Save***:
add fingerprint
certificate for SHA1
### Add Google Play sign-in provider Select ***Add new provider*** and choose ***Google Play***:
Choose Google Play
Activate ***Enable*** toggle, enter the credentials you just saved and choose ***Save***:
Play games setup
Both ***Google*** and ***Google Play*** sign-in providers are ready:
auth providers
### Install Openfort Extension Go to the [Firebase Extensions Hub](https://extensions.dev/extensions/openfort/firestore-openfort-transactions) and choose ***Install in Firebase console***:
extension hub
Choose your project to continue: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_38_129ce9d653.png?updated_at=2023-11-07T18:41:44.982Z) Set up your billing profile and follow the instructions until you need to insert the [Openfort API Secret key](https://dashboard.openfort.xyz/developers/api-keys) and choose ***Create secret***. Also set *Cloud Firestore* to ***Sync***:
configure extension
Finally choose ***Install extension***. After 3-5 minutes you will see the extension installed: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_41_9c8adab805.png?updated_at=2023-11-07T18:41:46.977Z) Now select ***Get started*** and under ***How this extension works*** section find ***Configure Openfort webhooks***. Copy the URL:
setup webhook
## Set up Openfort ### [Add webhook](https://dashboard.openfort.xyz/webhooks) Choose ***Add webhook***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_40_47d93997bf.png?updated_at=2023-11-07T18:41:38.486Z) Paste the webhook URL you got from the Firebase extension and leave the *Type* as it is. Choose ***Add webhook***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_44_f0baf395ee.png?updated_at=2023-11-07T18:41:44.581Z) ### [Add a Contract](https://dashboard.openfort.xyz/assets/new) Choose ***Add contract***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_45_dff8dbd5d9.png?updated_at=2023-11-09T04:23:43.095Z) This sample requires a contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (NFT contract deployed in 80002 Amoy). You can use the same for this tutorial: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_46_05a8645885.png?updated_at=2023-11-09T04:25:24.000Z) ### [Add a Policy](https://dashboard.openfort.xyz/policies/new) Choose ***Add policy***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_47_e043788f2d.png?updated_at=2023-11-09T04:27:17.395Z) We aim to cover gas fees for users. Set a new gas policy: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_48_3cd0914ae9.png?updated_at=2023-11-09T04:31:49.793Z) Now, add a rule so our contract uses this policy: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_49_74f55004ba.png?updated_at=2023-11-09T04:31:50.888Z) ## Set up Google Play > **Reminder:** Use the same Google account you used for setting up your Firebase app. ### Create a new app Go to [Play Console](https://play.google.com/console) and create a new app. Enter app details (it's important you select ***Game***), confirm policies and select ***Create app***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_12_0487318190.png?updated_at=2023-11-07T18:41:44.580Z) Under ***Grow --> Play Games Services --> Setup and management --> Configuration***, select ***Create new Play Games Services project*** and choose your Firebase project as the cloud project. Then select ***Use***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_13_5ad11592ff.png?updated_at=2023-11-07T18:41:47.787Z) ### Add credentials #### Add Android OAuth client credential Under ***Credentials*** section choose ***Add credential***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_14_7e4b6cb5d1.png?updated_at=2023-11-07T18:41:46.982Z) Select ***Android***:
add android credential
Scroll down and select ***Create OAuth client***:
create OAuth client
Choose ***Create OAuth Client ID***:
create OAuth client popup
This will open the Google Cloud console. Now select ***Android*** as *Application type*, enter a *Name* and fill the *Package name* with the **Unity app package name** (found in the Android Platform Player Settings):
setup client id gcp
![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_20_e3286e880c.png?updated_at=2023-11-07T18:41:47.076Z) Enter your [SHA1 certificate fingerprint](https://github.com/openfort-xyz/firebase-extension-unity-sample/tree/main#find-sha1-certificate-fingerprint) and choose ***CREATE***:
verify SHA1 create
Now you can download the JSON and choose ***OK***:
download JSON
Go back to the Google Play console, select ***Done*** and choose your newly created Android OAuth client. Then select ***Save changes***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_23_5ff3dc73de.png?updated_at=2023-11-07T18:41:44.877Z) #### Add Game server/Web OAuth client credential Go back to ***Configuration*** and select ***Add credential***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_24_b44fc158b9.png?updated_at=2023-11-07T18:41:44.287Z) Choose ***Game server***, refresh OAuth clients, select ***Web client (auto created by Google Service)*** (it was created automatically during [this process](https://github.com/openfort-xyz/firebase-extension-unity-sample/tree/main#add-google-sign-in-provider)) and select ***Save changes***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_25_1f76c7f29a.png?updated_at=2023-11-07T18:41:45.679Z) Finally copy the ***OAuth client ID***:
copy the oauth client
## Set up Unity project > **Reminder:** Make sure ***Android*** is selected as a platform in ***Build settings***. Go to ***Window --> Google Play Games --> Setup --> Android setup***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_30_818b8cbf6d.png?updated_at=2023-11-07T18:41:35.884Z) Paste the ***Game server OAuth client ID*** you just copied under ***Client ID***:
setup google play games
Go to the [Google Play console](https://play.google.com/console) and on your app's configuration select ***Get resources***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_32_52815075fc.png?updated_at=2023-11-07T18:41:44.377Z) Copy the Android (XML): ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_33_6690691229.png?updated_at=2023-11-07T18:41:38.876Z) In Unity, paste it in ***Resources Definition*** and then select ***Setup***:
setup google play games
Finally, go to the [Firebase console](https://console.firebase.google.com/?hl=es-419) and under your app configuration, download the ***google-services.json***: ![Alt text](https://blog-cms.openfort.xyz/uploads/firebase_extension_unity_img_36_5048e220db.png?updated_at=2023-11-07T18:41:46.980Z) Import it in your Unity project ***Assets*** folder to make sure every credential is up to date. ## Test on Android Upon building and running the game on an Android device, the registration/login process is automated via Google Play Games, resulting in a streamlined user experience. ## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and Firebase. Always remember to test every feature before deploying to guarantee a flawless player experience. ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/firebase-extension-unity-sample/issues). If you have questions, comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/backend/playfab.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate Playfab with Openfort', title: 'Integrate PlayFab in Unity', description: 'Learn how you can create your game in PlayFab with smart wallets.', subtitle: 'Learn how to integrate PlayFab backend and Openfort with your game', tocVideo: 'D_Ezeb4-U08', } ## Overview [PlayFab](https://playfab.com/) is a backend service provided by Microsoft for game developers, offering tools for live game management, all powered by Azure's cloud infrastructure. In this sample we use PlayFab's email & password authentication method to register a new user or log in with an existing one. Once authenticaded we use PlayFab's user identity token to create a non-custodial account using [Embedded Smart Accounts](https://www.openfort.xyz/blog/embedded-smart-accounts). Moreover, by integrating the [Openfort SDK](https://github.com/openfort-xyz/openfort-node) into Azure Functions, we establish a seamless connection to PlayFab. Unity clients using the PlayFab Unity SDK can tap into these functions, accessing the full range of Openfort features within the game environment. ## Application Workflow
Openfort PlayFab integration workflow
## Prerequisites + [Create a PlayFab account and title](https://learn.microsoft.com/en-us/gaming/playfab/gamemanager/quickstart) + Set up your Azure development environment: + [Configure your environment](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v4#configure-your-environment) + [Sign in to Azure](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v4#sign-in-to-azure) + [Create a function app](https://learn.microsoft.com/en-us/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v4#create-the-function-app-in-azure) + [Sign in to dashboard.openfort.xyz](http://dashboard.openfort.xyz) and create a new project + Download or clone the [sample project](https://github.com/openfort-xyz/playfab-unity-sample): + Open [unity-client](https://github.com/openfort-xyz/playfab-unity-sample/tree/main/unity-client) with Unity + Open [azure-backend](https://github.com/openfort-xyz/playfab-unity-sample/tree/main/azure-backend) with VS Code ## Set up Openfort 1. #### [Add PlayFab as a provider](https://dashboard.openfort.xyz/players/auth/providers) Add your PlayFab title and choose ***Save***:
PlayFab provider
2. #### [Create Shield Keys](https://dashboard.openfort.xyz/developers/api-keys) In order to create secure non-custodial accounts for our players, we need to create [Shield Keys](https://www.openfort.xyz/docs/api-keys#shield-secret-and-publishable-keys):
playfab_integration_1_a_fd65cb50f3
After the creation, it's very important you save **Shield Encryption Share Key**, you will need it later:
playfab_integration_1_b_b57537dc82
3. #### [Add a Contract](https://dashboard.openfort.xyz/assets) This sample requires a contract to run. We use [0x51216BFCf37A1D2002A9F3290fe5037C744a6438](https://sepolia.etherscan.io/address/0x51216BFCf37A1D2002A9F3290fe5037C744a6438) (NFT contract deployed in Sepolia - 11155111). You can use the same to ease up things:
playfab_integration_1_95cbd5e3b9
4. #### [Add a Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for users. Set a new gas policy:
playfab_integration_2_dc0ec65caa
Now, add a rule to make our contract benefit from it:
playfab_integration_3_8c21c821c5
## Deploy Azure Backend Open [azure-backend](https://github.com/openfort-xyz/playfab-unity-sample/tree/main/azure-backend) with VS Code and sign in to Azure:
playfab_integration_4_7deea77cf3
Ensure your Function App (here, it's "openfort-playfab") is listed:
playfab_integration_5_6d5e73b886
In the terminal, run: ``` npm install ``` In the explorer, right-click on a function and select ***Deploy to Function App***:
playfab_integration_6_ffc63d55ed
Next, choose your Function App:
playfab_integration_7_977d0a46c8
Then, click on ***Deploy***:
playfab_integration_8_1119fa1634
Navigate to your [Azure Portal](https://portal.azure.com/#home) and open your Function App. You should see all the functions listed:
playfab_integration_9_fb12c55de4
Click on any function and select ***Get Function Url***:
playfab_integration_10_c4ebde5781
Subsequently, add this URL (along with all others) to PlayFab to enable access to our Azure Functions from within PlayFab. ## Set up PlayFab Title 1. #### Register Azure Functions Visit the [PlayFab developer dashboard](https://developer.playfab.com/), choose your title, and click on ***Automation***:
playfab_integration_11_5615028c17
Our functions are already registered. To do the same, click ***Register function*** and provide the function name along with its URL:
playfab_integration_12_644b97fdaf
Repeat this for all deployed functions. ## Set up Azure Backend Our Azure backend requires environment variables from both PlayFab and Openfort. Let's configure them. 1. #### Add Openfort Environment Variables - Navigate to the [Azure Portal](https://portal.azure.com/#home) and select your Function App. - Under ***Settings --> Environment variables***, click ***Add***:
playfab_integration_13_c828ed6ed8
- Provide the following details: + Name: `OF_API_KEY` + Value: [Retrieve the **API Secret key**](https://dashboard.openfort.xyz/developers/api-keys) - Add another application setting: + Name: `OF_SHIELD_PUB_KEY` + Value: [Retrieve the **Shield Publishable Key**](https://dashboard.openfort.xyz/developers/api-keys) - Add another application setting: + Name: `OF_SHIELD_SECRET_KEY` + Value: [Retrieve the **Shield Secret Key**](https://dashboard.openfort.xyz/developers/api-keys) - Add another application setting: + Name: `OF_SHIELD_ENCRYPTION_SHARE` + Value: It's the **Shield Encryption Share Key** you saved before. - Add another application setting: + Name: `OF_NFT_CONTRACT` + Value: [Retrieve the **Contract API ID**](https://dashboard.openfort.xyz/assets) - Add another application setting: + Name: `OF_SPONSOR_POLICY` + Value: [Retrieve the **Policy API ID**](https://dashboard.openfort.xyz/policies) - And another application setting: + Name: `OF_CHAIN_ID` + Value: 11155111 2. #### Add PlayFab Environment Variables - Visit the [PlayFab developer dashboard](https://developer.playfab.com/), select your title, and navigate to ***Settings wheel --> Title settings***:
playfab_integration_14_5bc8927522
- In the ***API Features*** section, copy your ***Title ID***:
playfab_integration_15_711115c4a8
- Under ***Secret Keys***, note down your ***Secret key***:
playfab_integration_16_56663676c7
- Return to the [Azure Portal](https://portal.azure.com/#home) and choose your Function App. - Under ***Settings --> Environment variables***, click ***Add***: + Name: `PLAYFAB_TITLE_ID` + Value: [Your Title ID] - Add another application setting: + Name: `PLAYFAB_SECRET_KEY` + Value: [Your Secret Key] After adding all the environment variables, your configuration panel should look like the following. Confirm your changes by clicking ***Save***:
playfab_integration_17_6748a73edf
## Set up Unity Client This Unity sample project is already equipped with: + [PlayFab Unity SDK](https://github.com/PlayFab/UnitySDK) + [Openfort SDK](https://github.com/openfort-xyz/openfort-csharp-unity) To begin, open [unity-client](https://github.com/openfort-xyz/playfab-unity-sample/tree/main/unity-client) with Unity: 1. #### Configure PlayFab SDK - Navigate to the ***Project*** tab. - Search for `PlayFabSharedSettings` and input your PlayFab ***Title ID***:
playfab_integration_18_591d3cad7d
2. #### Configure Openfort SDK - Open the *Login scene* and add the **API Publishable Key** and the **Shield Publishable Key** to the *OpenfortController* config section:
playfab_integration_19_24bc025e75
## Test in Editor Play ***Login*** scene, opt for ***Register***, provide an email and password, then click ***Register*** again. This scene should appear:
playfab_integration_20_f934393700
Select ***Mint***. After a brief period, you should see a representation of your newly minted NFT:
playfab_integration_21_8213efd860
In the [Openfort Players dashboard](https://dashboard.openfort.xyz/players), a new player entry should be visible. On selecting this player:
playfab_integration_22_1b307cda7e
You'll notice that a `mint` transaction has been successfully processed:
playfab_integration_23_eca707b92d
Additionally, by choosing your **Sepolia Wallet Address**, the explorer will open and by selecting ***NFT Transfers*** tab you'll see the transaction is further confirmed:
playfab_integration_24_f29150e8b8
playfab_integration_25_8aa4b7ec6a
## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and PlayFab. Always remember to test every feature before deploying to guarantee a flawless player experience. ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/playfab-unity-sample/issues). If you have questions, comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/backend/unity-gaming-services.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate Unity Gaming Services with Openfort', title: 'Integrate Unity Gaming Services (UGS) in Unity', description: 'Learn how you can create your game in Unity Gaming Services with a blockchain integration with Openfort.', subtitle: 'Learn how to integrate UGS backend and Openfort with your game', tocVideo: 'Anl9X253RC8', } ## Overview This is a sample project to showcase the Openfort integration with [Unity Gaming Services](https://unity.com/solutions/gaming-services), a complete service ecosystem for Unity live games. The sample includes: - [**`ugs-backend`**](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/ugs-backend) A .NET Core project with [Cloud Code C# modules](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules#Cloud_Code_C#_modules) that implement [Openfort C# SDK](https://www.nuget.org/packages/Openfort.SDK/1.0.21) methods. Hosted in UGS. - [**`unity-client`**](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/unity-client) A Unity sample game that connects to ``ugs-backend`` through [Cloud Code](https://docs.unity.com/ugs/manual/cloud-code/manual). It uses [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) to deserialize its responses. The sample uses [Unity Authentication](https://docs.unity.com/ugs/en-us/manual/authentication/manual/get-started) to sign in as a new anonymous player. It then [creates an Openfort player](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/ab1a5f69346910c18ea88579f6fce81cdcde489a/ugs-backend/CloudCodeModules/PlayersModule.cs#L31) and a [custodial account](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/ab1a5f69346910c18ea88579f6fce81cdcde489a/ugs-backend/CloudCodeModules/PlayersModule.cs#L38) using Openfort and it [links it](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/ab1a5f69346910c18ea88579f6fce81cdcde489a/ugs-backend/CloudCodeModules/PlayersModule.cs#L43) to the Unity player. Then the player can frictionlessly [mint an NFT](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/ab1a5f69346910c18ea88579f6fce81cdcde489a/ugs-backend/CloudCodeModules/MintingModule.cs#L26). ## Application Workflow
Integration workflow
## Prerequisites + **Get started with Openfort** + [Sign in](https://dashboard.openfort.xyz/login) or [sign up](https://dashboard.openfort.xyz/register) and create a new dashboard project + **Get started with UGS** + [Complete basic prerequisites](https://docs.unity.com/ugs/manual/overview/manual/getting-started#Prerequisites) + [Create a project](https://docs.unity.com/ugs/manual/overview/manual/getting-started#CreateProject) ## Setup Openfort dashboard + [Add a Contract](https://dashboard.openfort.xyz/assets/new) This sample requires a contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (NFT contract deployed in 80002 Amoy). You can use this for the guide:
Contract Info
+ [Add a Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for users. Set a new gas policy:
Gas Policy
Now, add a rule so our contract uses this policy:
Policy Rule
## Set up [`ugs-backend`](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/ugs-backend) - ### Set Openfort dashboard variables Open the [solution](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/main/ugs-backend/CloudCodeModules.sln) with your preferred IDE, open [``SingletonModule.cs``](https://github.com/openfort-xyz/ugs-unity-game-services-sample/blob/main/ugs-backend/CloudCodeModules/CloudCodeModules.csproj) and fill in these variables:
Singleton Module
- [Retrieve the **Secret key**](https://dashboard.openfort.xyz/developers/api-keys) - [Retrieve the **Contract API ID**](https://dashboard.openfort.xyz/assets) - [Retrieve the **Policy API ID**](https://dashboard.openfort.xyz/policies) - ### Package Code Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Package_code). - ### Deploy to UGS Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Deploy_a_module_project). ## Set up [``unity-client``](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/unity-client) Follow the [official documentation steps](https://docs.unity.com/ugs/manual/authentication/manual/get-started#Link_your_project) to link the ``unity-client`` to your UGS Project ID. ## Test in Editor Play the **Main** scene and click ***Sign in*** button. After some authentication-related logs, this panel should appear:
Game Scene
Select ***Mint***. After a brief period, you should see a representation of your newly minted NFT:
Mint Panel
In the [Openfort Players dashboard](https://dashboard.openfort.xyz/players), a new player entry should be visible. On selecting this player:
Player Entry
You'll notice that a `mint` transaction has been successfully processed:
Mint Transaction
Additionally, by choosing your **Amoy Account** and viewing ***NFT Transfers***, the transaction is further confirmed:
Etherscan
Keep in mind that the sample is designed so a player can mint only once. By default, UGS Authentication will use the same player per device. If you want to sign in with a new player check the ***Clear Session Token*** in ***AuthController***:
Clear Session Token
## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and UGS. Always remember to test every feature before deploying to guarantee a flawless player experience. For a deeper understanding of the underlying processes, check out the [tutorial video](https://youtu.be/PHNodBmbEfA). ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/ugs-unity-game-services-sample/issues). If you have questions, or comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/ads-unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Ads in Unity to pay for Gas Fees', title: 'Game ads in Unity to pay for gas fees', description: 'Learn how to use game Ads to pay for gas fees', subtitle: 'Integrate game ads in your web3 game.', tocVideo: 'vjjvDILS-DU', } ## Overview This sample project showcases the Openfort integration with [Unity LevelPlay](https://docs.unity.com/monetization-dashboard/en-us/manual/UnityLevelPlay). The sample includes: - [**`ugs-backend`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) A .NET Core project with [Cloud Code C# modules](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules#Cloud_Code_C#_modules) that implement [Openfort C# SDK](https://www.nuget.org/packages/Openfort.SDK/1.0.21) methods. Needs to be hosted in Unity Gaming Services. - [**`unity-client`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) A Unity sample game that connects to ``ugs-backend`` through [Cloud Code](https://docs.unity.com/ugs/manual/cloud-code/manual). It uses [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) to have full compatibility with `ugs-backend` responses. ## Application Workflow
Integration workflow
## Prerequisites + **Get started with Openfort** + [Sign in](https://dashboard.openfort.xyz/login) or [sign up](https://dashboard.openfort.xyz/register) and create a new dashboard project + **Get started with UGS** + [Complete basic prerequisites](https://docs.unity.com/ugs/manual/overview/manual/getting-started#Prerequisites) + **Get started with ironSource**: + [Sign up](https://developers.is.com/ironsource-mobile/air/sign-up-ironsource/) on the ironSource website ## Set up Openfort dashboard + [Add an NFT contract](https://dashboard.openfort.xyz/assets/new) This sample requires an NFT contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (contract deployed in 80002 Amoy). You can use it for this tutorial too:
Contract Info
+ [Add an ERC20 contract](https://dashboard.openfort.xyz/assets/new) This sample also requires an ERC20 contract to run. You can [deploy a standard one](https://thirdweb.com/thirdweb.eth/TokenERC20) and then add it to the Openfort dashboard following the same logic as above. + [Add a Full Sponsor Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for our players when they mint the NFT (if they have watched the ad video). Set a new gas policy for that:
Gas Policy
Add a rule so the NFT contract uses this policy:
NFT Policy Rule
Add also a rule for the ERC20 contract, as we want to send some ERC20 tokens to the player to be able to test the sample:
ERC20 Policy Rule
+ [Add a Fixed Charge Policy](https://dashboard.openfort.xyz/policies/new) The players will be charged with 1 in-game ERC20 token when they decide not to watch the ad:
Fixed charge policy
Add a rule so the policy applies to the NFT contract:
NFT Policy Rule
+ [Add a Developer Account](https://dashboard.openfort.xyz/accounts) Enter a name and choose ***Add account***:
Developer account
This will automatically create a custodial wallet that we'll use to send the ERC20 tokens to the players. **IMPORTANT: Transfer a good amount of tokens from the created ERC20 contract to this wallet to facilitate testing**. ## Set up ironSource - ### Get Unity Cloud keys Before going into ironSource, go to the [Unity Cloud dashboard](https://cloud.unity.com/) and open ***Unity Ads Monetization*** using *Shortcuts*:
Unity Cloud dashboard: Unity Ads Monetization
- #### Create a LevelPlay Service Account Now go to the ***API management*** section and choose ***Create LevelPlay Service Account***:
Unity Cloud dashboard: Create LevelPlay Service Account
Copy and save the ***Key ID*** and the ***Secret key*** somewhere safe and choose ***Done***:
Unity Cloud dashboard: Copy LevelPlay Service Account credentials
- #### Get Monetization Stats API Access Copy and save the API Key. Choose ***Create API Key*** if it's not already there:
Unity Cloud dashboard: copy Monetization Stats API key
- #### Get Organization Core ID Copy and save the Organization Core ID:
Unity Cloud dashboard: copy Organization Core ID
- ### Create an ironSource LevelPlay app Go to the [ironSource dashboard](https://platform.ironsrc.com/partners/dashboard) and under the *LevelPlay* section, choose ***Add app*** and enter your app details:
ironSource: new app
Select the following settings and choose ***Add app***:
ironSource: app details
Activate ***Rewarded Video*** as an ad unit and choose ***Continue***:
ironSource: activate ad units
- ### Set up SDK Networks In the *Available Networks* panel select ***Unity Ads***:
ironSource: available networks
Enable the ***Unity bidder auto-setup*** option, add all the credentials from the [*Get Unity Cloud keys* section](https://github.com/openfort-xyz/unity-ad-sample#get-unity-cloud-keys) and choose ***Save***:
ironSource: adding Unity Ads
*Unity Ads* will have appeared as a new available network. Choose ***Setup***:
ironSource: setup Unity Ads
Because we enabled the *Unity bidder auto-setup* option, now you can choose ***Add bidder***:
ironSource: add bidder
The needed information from Unity will be automatically retrieved. Choose ***Save***:
ironSource: save app
## Set up Unity Cloud Thanks to the *Unity bidder auto-setup* option, a new project has been automatically created in the [Unity Cloud dashboard](https://cloud.unity.com/). Now your LevelPlay Service Account needs to have some admin roles over this newly created project. Go to ***Administration --> Service accounts*** and choose your account:
Set up Unity Cloud: service account
Scroll down and choose ***Manage project roles***:
Set up Unity Cloud: manage project roles
Select your project and choose ***Next***:
Set up Unity Cloud: select project
In the *Admin* dropdown select: + ***Player Resource Policy Editor*** + ***Project Resource Policy Editor*** + ***Unity Environments Admin*** In the *LiveOps* dropdown select: + ***Cloud Code Script Publisher*** + ***Triggers Configuration Editor*** + ***Leaderboards Admin*** + ***Cloud Code Editor*** Choose ***Save***:
Set up Unity Cloud dashboard: add roles
## Set up [`ugs-backend`](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) - ### Set Openfort dashboard variables Open the [solution](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules.sln) with your preferred IDE, open [``SingletonModule.cs``](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/SingletonModule.cs) and fill in these variables:
Singleton Module
- `OfApiKey`: [Retrieve the **Openfort secret key**](https://dashboard.openfort.xyz/developers/api-keys) - `OfNftContract`: [Retrieve the **NFT contract API ID**](https://dashboard.openfort.xyz/assets) - `OfGoldContract`: [Retrieve the **ERC20 contract API ID**](https://dashboard.openfort.xyz/assets) - `OfFullSponsorPolicy`: [Retrieve the **Full Sponsor Policy API ID**](https://dashboard.openfort.xyz/policies) - `OfChargeErc20Policy`: [Retrieve the **Fixed Charge Policy API ID**](https://dashboard.openfort.xyz/policies) - `OfDevAccount`: [Retrieve the **Developer Account API ID**](https://dashboard.openfort.xyz/accounts) - ### Package Code Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Package_code). - ### Deploy to UGS Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Deploy_a_module_project). ## Set up [``unity-client``](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) In Unity go to *Edit --> Project Settings --> Services* and link the ``unity-client`` to your UGS Project:
Services settings
Select your *Environment*:
UGS environment
Under *Assets --> Scripts --> Controllers* open the ***AdsController.cs***:
AdsController.cs
Fill the **``appKey``** variable with the *ironSource LevelPlay app key* and save the script:
ironSource LevelPlay app key
ironSource LevelPlay app key
## Build to Android In Unity go to [*Android Player settings*](https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html) and make sure *Other Settings* looks like this:
Android Player settings
Also, make sure to sign the application with a [Keystore](https://docs.unity3d.com/Manual/android-keystore-create.html) in *Publishing Settings*:
Application Signing
Return to *Build Settings* and choose ***Build***:
Build
Send and run the *.apk* on your device. ## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and [Unity LevelPlay](https://docs.unity.com/monetization-dashboard/en-us/manual/UnityLevelPlay). Always remember to test every feature before deploying to guarantee a flawless player experience. For a deeper understanding of the underlying processes, check out the [tutorial video](https://www.youtube.com/watch?v=vjjvDILS-DU). ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/iap-unity-sample/issues). If you have questions, or comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/android-iap-unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate Android In-App Purchases in Unity', title: 'Integrate Android In-App Purchases (IAP) in Unity', description: 'Learn how you can integrate IAP in your game in Unity and UGS.', subtitle: 'Integrate Android IAP in your web3 game.', tocVideo: '8Pw4VUyWVY8', } ## Overview This sample project showcases the Openfort integration with Android [In-App Purchasing](https://docs.unity3d.com/Packages/com.unity.purchasing@4.10/manual/Overview.html) in Unity. The sample includes: - [**`ugs-backend`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) A .NET Core project with [Cloud Code C# modules](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules#Cloud_Code_C#_modules) that implement [Openfort C# SDK](https://www.nuget.org/packages/Openfort.SDK/1.0.21) methods. Needs to be hosted in Unity Gaming Services. - [**`unity-client`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) A Unity sample game that connects to ``ugs-backend`` through [Cloud Code](https://docs.unity.com/ugs/manual/cloud-code/manual). It uses [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) to have full compatibility with `ugs-backend` responses. ## Application Workflow
Integration workflow
## Workflow 1. [Sign in as a new anonymous player](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/AuthController.cs#L44) 2. [Create an Openfort player](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/PlayersModule.cs#L59) and a [custodial account](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/PlayersModule.cs#L66) 3. [Save the Openfort player's information](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/PlayersModule.cs#L72) to the Unity player's dashboard 4. [Initialize Unity In-App Purchasing service](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/ShopController.cs#L44) 5. Now the player can [purchase a consumable or a non-consumable in-app product](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/ShopController.cs#L74) 6. [If the consumable purchase is successful](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/ShopController.cs#L124), some [ERC20 tokens will be transferred](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/TransferModule.cs#L31) to its account 7. [If the non-consumable purchase is successful](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/ShopController.cs#L127), the player will [mint an NFT](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/MintingModule.cs#L25) 8. The player can also [retrieve their ERC20 token balance](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/InventoryController.cs#L56) and [NFT inventory](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/Scripts/Controllers/InventoryController.cs#L24) ## Prerequisites + **Get started with Openfort** + [Sign in](https://dashboard.openfort.xyz/login) or [sign up](https://dashboard.openfort.xyz/register) and create a new dashboard project + **Get started with UGS** + [Complete basic prerequisites](https://docs.unity.com/ugs/manual/overview/manual/getting-started#Prerequisites) + [Create a project](https://docs.unity.com/ugs/manual/overview/manual/getting-started#CreateProject) + **Get started with Google Play Console** + [Create and set up your app](https://support.google.com/googleplay/android-developer/answer/9859152?hl=en) ## Setup Openfort dashboard + [Add an NFT contract](https://dashboard.openfort.xyz/assets/new) This sample requires an NFT contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (contract deployed in 80002 Amoy). You can use it for this tutorial too:
Contract Info
+ [Add an ERC20 contract](https://dashboard.openfort.xyz/assets/new) This sample also requires an ERC20 contract to run. You can [deploy a standard one](https://thirdweb.com/thirdweb.eth/TokenERC20) and then add it to the Openfort dashboard following the same logic as above. + [Add a Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for our users when they mint the NFT. Set a new gas policy for that:
Gas Policy
Add a rule so the NFT contract uses this policy:
NFT Policy Rule
Add also a rule for the ERC20 contract:
ERC20 Policy Rule
+ [Add a Developer Account](https://dashboard.openfort.xyz/accounts) Enter a name and choose ***Add account***:
Developer account
This will automatically create a custodial wallet that we'll use to send the ERC20 tokens to the players. **IMPORTANT: Transfer a good amount of tokens from the created ERC20 contract to this wallet to facilitate testing**. ## Set up [`ugs-backend`](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) - ### Set Openfort dashboard variables Open the [solution](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules.sln) with your preferred IDE, open [``SingletonModule.cs``](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/SingletonModule.cs) and fill in these variables:
Singleton Module
- `OfApiKey`: [Retrieve the **Openfort secret key**](https://dashboard.openfort.xyz/developers/api-keys) - `OfNftContract`: [Retrieve the **NFT contract API ID**](https://dashboard.openfort.xyz/assets) - `OfGoldContract`: [Retrieve the **ERC20 contract API ID**](https://dashboard.openfort.xyz/assets) - `OfSponsorPolicy`: [Retrieve the **Policy API ID**](https://dashboard.openfort.xyz/policies) - `OfDevAccount`: [Retrieve the **Developer Account API ID**](https://dashboard.openfort.xyz/accounts) - ### Package Code Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Package_code). - ### Deploy to UGS Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Deploy_a_module_project). ## Set up [``unity-client``](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) In Unity go to *Edit --> Project Settings --> Services* and link the ``unity-client`` to your UGS Project:
Services settings
Select your *Environment*:
UGS environment
Now make sure *In-App Purchasing* is enabled and *Current Targeted Store* is set to ***Google Play***. Then follow the instructions to set the **Google Play License Key** to your UGS project:
Google Play License Key
Your UGS project dashboard should look like this:
License key in UGS dashboard
## Test in Editor Play the **Main** scene and you should see the sign-in panel:
Sign in panel
Choose ***Sign in***. The first time it will create a new player but the next time it will sign in as the same player. After some authentication-related logs, this panel should appear:
Game Scene
Here you have two options: + Purchase ERC20 tokens (x10) + Purchase NFT By clicking any of them, a *Fake Store* panel will pop up, letting you confirm or cancel the purchase:
Game Scene
If you confirm, after a brief period you should see the *Transaction successful* message:
Game Scene
You can then click on the inventory icon to see the representation of your on-chain assets:
Game Scene
In the [Openfort Players dashboard](https://dashboard.openfort.xyz/players), a new player entry should be visible. On selecting this player:
Player Entry
You'll notice that a `mint` transaction has been successfully processed:
Mint Transaction
Additionally, by choosing your **Amoy Account** and viewing ***NFT Transfers***, the transaction is further confirmed:
Etherscan
## Build App Bundle In Unity go to [*Android Player settings*](https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html) and make sure *Other Settings* looks like this:
Android Player settings
Also, make sure to sign the application with a [Keystore](https://docs.unity3d.com/Manual/android-keystore-create.html) in *Publishing Settings*:
Application Signing
Then go to *Build Settings*, check ***Build App Bundle (Google Play)*** and choose ***Build***:
Build
## Set up Google Play Console - ### Create internal release On your [Google Play Console](https://play.google.com/console/u/0/developers/7556582789169418933?onboardingflow=signup) app, go to *Release --> Testing --> Internal testing --> Testers* and select or create an email list with the emails that will test your app. Then choose ***Create new release***:
New release
Upload the `.aab` file and then choose ***Next***:
Upload build
If needed, solve pending errors and warnings and then choose ***Save and publish***:
Save and publish
- ### Import IAP catalog On your [Google Play Console](https://play.google.com/console/u/0/developers/7556582789169418933?onboardingflow=signup) app, go to *Monetize --> Products --> In-app products* and choose ***Import***:
Create product
Upload the [``GooglePlayProductCatalog.csv``](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/GooglePlayProductCatalog.csv) file (which contains all the in-app products) and choose ***Import***:
Import products
You should see all the products have been created:
Products created
## Test in Android Once the internal testing release is published, you have two options to test: - Build and run the .apk directly to your device ([if the *version number* is the same as in the internal release](https://docs.unity3d.com/Packages/com.unity.purchasing@4.10/manual/Testing.html)). - Download the app from Google Play through the internal testing link:
Internal testing link
## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and Unity In-App Purchasing service. Always remember to test every feature before deploying to guarantee a flawless player experience. For a deeper understanding of the underlying processes, check out the [tutorial video](https://youtu.be/8Pw4VUyWVY8). ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/iap-unity-sample/issues). If you have questions, or comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/apple-iap-unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate Apple In-App Purchases (IAP) in Unity', title: 'In-App (IAP) Purchases in Unity', description: 'Learn how you can integrate IAP in your game in Unity and UGS.', subtitle: 'Integrate IAP flows in your mobile game - Apple and Android', tocVideo: '37yAu7YQXhg', } ## Overview *Disclaimer: Openfort is not responible of such integration to be approved by Apple and/or Google* This sample project showcases the Openfort advanced & compliant integration with [In-App Purchasing](https://docs.unity3d.com/Packages/com.unity.purchasing@4.10/manual/Overview.html) in Unity. The objective of this integration sample is to implement and showcase a **crypto In-App Purchasing system** compliant with the [rules/guidelines]() companies like Apple have set for this type of purchases in mobile apps. ## Specifications The sample includes: - [**`ugs-backend`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) A .NET Core project with [Cloud Code C# modules](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules#Cloud_Code_C#_modules) that implement [Openfort C# SDK](https://www.nuget.org/packages/Openfort.SDK/1.0.21) methods. Needs to be hosted in Unity Gaming Services. - [**`unity-client`**](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) A Unity sample game that connects to ``ugs-backend`` through [Cloud Code](https://docs.unity.com/ugs/manual/cloud-code/manual). It uses [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) to have full compatibility with `ugs-backend` responses. ## Application Workflow
Openfort In-App Purchase Advanced Sample workflow
## Prerequisites + **Get started with Openfort** + [Sign in](https://dashboard.openfort.xyz/login) or [sign up](https://dashboard.openfort.xyz/register) and create a new dashboard project + **Get started with UGS** + [Complete basic prerequisites](https://docs.unity.com/ugs/manual/overview/manual/getting-started#Prerequisites) + [Create a project](https://docs.unity.com/ugs/manual/overview/manual/getting-started#CreateProject) + **Get started with Google Play Console** + [Create and set up your app](https://support.google.com/googleplay/android-developer/answer/9859152?hl=en) + **Get started with Apple Developer Account** + [Set up everything needed for Apple development](https://developer.apple.com/help/account/) + Make sure to [sign the Paid Apps agreement](https://developer.apple.com/help/app-store-connect/manage-agreements/sign-and-update-agreements) and fill tax and banking details as it's needed for testing IAP. ## Setup Openfort dashboard + [Add an NFT contract](https://dashboard.openfort.xyz/assets/new) This sample requires an NFT contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (contract deployed in 80002 Amoy). You can use it for this tutorial too:
Contract Info
+ [Add an ERC20 contract](https://dashboard.openfort.xyz/assets/new) This sample also requires an ERC20 contract to run. You can [deploy a standard one](https://thirdweb.com/thirdweb.eth/TokenERC20) and then add it to the Openfort dashboard following the same logic as above. + [Add a Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for our users when they mint the NFT. Set a new gas policy for that:
Gas Policy
Add a rule so the NFT contract uses this policy:
NFT Policy Rule
Add also a rule for the ERC20 contract:
ERC20 Policy Rule
+ [Create two backend wallets](https://dashboard.openfort.xyz/accounts)
Backend wallet
1. Enter a name (treasure account) and click ***Add account***. This will automatically create a custodial wallet that we'll use to transfer the ERC20 tokens to the players. **IMPORTANT: Transfer a good amount of tokens from the created ERC20 contract to this wallet to facilitate testing**. 2. Enter a name (minting account) and click ***Add account***. This will automatically create a custodial wallet that the players will transfer the NFTs to when they choose the sell them. They'll get rewarded from the Treasury Dev Account afterwards. ## Set up [`ugs-backend`](https://github.com/openfort-xyz/iap-unity-sample/tree/main/ugs-backend) - ### Set Openfort dashboard variables Open the [solution](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules.sln) with your preferred IDE, open [``SingletonModule.cs``](https://github.com/openfort-xyz/iap-unity-sample/blob/main/ugs-backend/CloudCodeModules/SingletonModule.cs) and fill in these variables:
Singleton Module
- `OfApiKey`: [Retrieve the **Openfort secret key**](https://dashboard.openfort.xyz/developers/api-keys) - `OfNftContract`: [Retrieve the **NFT contract API ID**](https://dashboard.openfort.xyz/assets) - `OfGoldContract`: [Retrieve the **ERC20 contract API ID**](https://dashboard.openfort.xyz/assets) - `OfSponsorPolicy`: [Retrieve the **Policy API ID**](https://dashboard.openfort.xyz/policies) - `OfDevTreasuryAccount`: [Retrieve the **Treasury Developer Account API ID**](https://dashboard.openfort.xyz/accounts) - `OfDevMintingAccount`: [Retrieve the **Minting Developer Account API ID**](https://dashboard.openfort.xyz/accounts) - ### Package Code Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Package_code). - ### Deploy to UGS Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/modules/getting-started#Deploy_a_module_project). - ### Add a currency to UGS project Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/economy/manual/add-currency) to add a currency to your game:
UGS currency
## Set up [``unity-client``](https://github.com/openfort-xyz/iap-unity-sample/tree/main/unity-client) In Unity go to *Edit --> Project Settings --> Services* and link the ``unity-client`` to your UGS Project:
Services settings
Select your *Environment*:
UGS environment
Now make sure *In-App Purchasing* is enabled and *Current Targeted Store* is set to ***Google Play***. Then follow the instructions to set the **Google Play License Key** to your UGS project:
Google Play License Key
Your UGS project dashboard should look like this:
License key in UGS dashboard
**Apple AppStore** doesn't need this *license key configuration* so if you're targeting **iOS** you're good to go. ## Android deployment + ### Build App Bundle In Unity go to [*Android Player settings*](https://docs.unity3d.com/Manual/class-PlayerSettingsAndroid.html) and make sure *Other Settings* looks like this:
Android Player settings
Also, make sure to sign the application with a [Keystore](https://docs.unity3d.com/Manual/android-keystore-create.html) in *Publishing Settings*:
Application Signing
Then go to *Build Settings*, check ***Build App Bundle (Google Play)*** and choose ***Build***:
Build
+ ### Set up Google Play Console - #### Create internal release On your [Google Play Console](https://play.google.com/console/u/0/developers/7556582789169418933?onboardingflow=signup) app, go to *Release --> Testing --> Internal testing --> Testers* and select or create an email list with the emails that will test your app. Then choose ***Create new release***:
New release
Upload the `.aab` file and then choose ***Next***:
Upload build
If needed, solve pending errors and warnings and then choose ***Save and publish***:
Save and publish
- #### Import IAP catalog On your [Google Play Console](https://play.google.com/console/u/0/developers/7556582789169418933?onboardingflow=signup) app, go to *Monetize --> Products --> In-app products* and choose ***Import***:
Create product
Upload the [``GooglePlayProductCatalog.csv``](https://github.com/openfort-xyz/iap-unity-sample/blob/main/unity-client/Assets/GooglePlayProductCatalog.csv) file (which contains all the in-app products) and choose ***Import***:
Import products
You should see all the products have been created:
Products created
+ ### Testing Once the internal testing release is published, you have two options to test: - Build and run the .apk directly to your device ([if the *version number* is the same as in the internal release](https://docs.unity3d.com/Packages/com.unity.purchasing@4.10/manual/Testing.html)). - Download the app from Google Play through the internal testing link:
Internal testing link
## iOS deployment + ### Xcode: Build & Archive & Upload In Unity go to *File --> Build Settings* and choose ***Build And Run***:
Build to Xcode
This will automatically open Xcode. If you encounter a `signing error`, select your development team and enable ***Automatically manage signing***:
Build to Xcode: error
Start the building process again **(cmd + B)** and when completed, go to ***Product --> Archive***:
Build to Xcode: archive
After completing, choose ***Distribute App***:
Build to Xcode: Distribute app
Select ***TestFlight & App Store*** to enable both internal and external testing and choose ***Distribute***:
Build to Xcode: distribute
The app will be uploaded to **App Store Connect**:
Build to Xcode: complete
+ ### Set up App Store Connect app Go to [App Store Connect Apps](https://appstoreconnect.apple.com/apps), choose your newly uploaded app and under **Distribution --> In-App Purchases** add the purchases:
Build to Xcode: in-app purchases
Remember to fill the same *Product ID* as you have set in your **Unity IAP Catalog**. Do it for all your products:
Build to Xcode: catalog
Go to the *TestFlight section* and choose ***Manage Missing Compliance*** for your build:
Build to Xcode: catalog
+ ### Testing Go to *Internal Testers* ([add testers](https://developer.apple.com/help/app-store-connect/test-a-beta-version/add-testers-to-builds/)) and you should see your build ready to be tested:
Build to Xcode: testers
Open the TestFlight in the iOS device where your tester Apple ID is configured and test the app! ## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and Unity In-App Purchasing service. Always remember to test every feature before deploying to guarantee a flawless player experience. For a deeper understanding of the underlying processes, check out the [tutorial video](https://www.youtube.com/watch?v=37yAu7YQXhg). ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/samples/issues). If you have questions, or comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/captcha-unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Integrate Unity reCAPTCHA V3 Sample', title: 'Add reCAPTCHA in your Unity game', description: 'Learn how to use use CAPTCHA to block bot behaviour', subtitle: 'Learn how to integrate reCATPCHA in your game', } ## Overview This is a sample project to showcase the Openfort integration with [Google reCAPTCHA V3](https://developers.google.com/recaptcha/docs/v3), a system to help you protect your sites from fraudulent activities, spam, and abuse. In this sample, we will activate reCAPTCHA verification every time the user tries to perform a key action like authenticating or minting an NFT. The sample includes: - [**`ugs-backend`**](https://github.com/openfort-xyz/unity-recaptcha-sample/tree/main/ugs-backend) Some [Cloud Code JS scripts](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/scripts) to interact with the Openfort API from UGS BaaS. - [**`unity-client`**](https://github.com/openfort-xyz/unity-recaptcha-sample/tree/main/unity-client) A Unity sample game that connects to ``ugs-backend`` through [Cloud Code Client SDK](https://docs.unity.com/ugs/manual/cloud-code/manual). It uses [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) to have full compatibility with ``ugs-backend`` responses. ## Workflow diagram
Openfort Unity reCAPTCHA V3 Sample Workflow
## Prerequisites + **Get started with Openfort** + [Sign in](https://dashboard.openfort.xyz/login) or [sign up](https://dashboard.openfort.xyz/register) and create a new dashboard project + **Get started with UGS** + [Complete basic prerequisites](https://docs.unity.com/ugs/manual/overview/manual/getting-started#Prerequisites) + [Create a project](https://docs.unity.com/ugs/manual/overview/manual/getting-started#CreateProject) + **Get started with GitHub Pages** + [Create a repository for your site](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site#creating-a-repository-for-your-site) + [Create your site](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site#creating-your-site) ## Setup Openfort dashboard + [Add a Contract](https://dashboard.openfort.xyz/assets/new) This sample requires an NFT contract to run. We use [0xbed6a05ce8719bc00db1cc81a814192c82be1bb1](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1) (NFT contract deployed in 80002 Amoy). You can use it for this tutorial:
Contract Info
+ [Add a Policy](https://dashboard.openfort.xyz/policies/new) We aim to cover gas fees for users. Set a new gas policy:
Gas Policy
Now, add a rule so our contract uses this policy:
Policy Rule
## Set up reCAPTCHA V3 Go to [reCAPTCHA v3 Admin Console](https://www.google.com/recaptcha/admin) to register a new site. Choose ***Switch to create a classic key*** if the option is available:
Set up reCAPTCHA V3: Switch to create a classic key
Enter a ***Label*** name, select the ***reCAPTCHA type*** and enter your GitHub Pages URL as a ***Domain***:
Set up reCAPTCHA V3: Fill options
Accept the terms of service and choose ***Submit***:
Set up reCAPTCHA V3: Submit
Copy the ***Site Key*** and the ***Secret Key*** and save them somewhere safe:
Set up reCAPTCHA V3: Copy keys
## Set up [`ugs-backend`](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/ugs-backend) - ### Fill in environment variables + [Retrieve the **API Secret key**](https://dashboard.openfort.xyz/developers/api-keys) and fill in the [``openfortApiKey``](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/55f91101ff4eae301b6d8c98458023c6b3b34d6e/ugs-backend/CreateOpenfortPlayer.js#L5) variable. + [Use the same **API Secret key**](https://dashboard.openfort.xyz/developers/api-keys) to fill the [``openfortApiKey``](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/55f91101ff4eae301b6d8c98458023c6b3b34d6e/ugs-backend/MintNft.js#L5) variable. + [Retrieve the **NFT Contract API ID**](https://dashboard.openfort.xyz/assets) and fill in the [``nftContractId``](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/55f91101ff4eae301b6d8c98458023c6b3b34d6e/ugs-backend/MintNft.js#L9C11-L9C25) variable. + [Retrieve the **Policy API ID**](https://dashboard.openfort.xyz/policies) and fill in the [``policyId``](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/55f91101ff4eae301b6d8c98458023c6b3b34d6e/ugs-backend/MintNft.js#L10C11-L10C19) variable. + Fill in the [``secretKey``](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/55f91101ff4eae301b6d8c98458023c6b3b34d6e/ugs-backend/VerifyReCaptcha.js#L6) with your **reCAPTCHA secret key**. - ### Deploy to UGS Follow [the official documentation steps](https://docs.unity.com/ugs/en-us/manual/cloud-code/manual/scripts/getting-started#Deploy_a_Cloud_Code_script) to deploy each and all of the Cloud Code scripts. ## Set up [``unity-client``](https://github.com/openfort-xyz/ugs-unity-game-services-sample/tree/main/unity-client) - ### Link to UGS project Follow the [official documentation steps](https://docs.unity.com/ugs/manual/authentication/manual/get-started#Link_your_project) to link the ``unity-client`` to your UGS Project. - ### Fill in needed variables On the [Main scene](https://github.com/openfort-xyz/unity-recaptcha-sample/tree/main/unity-client/Assets/Scenes), select the *ReCaptchaController* game object and fill in your **reCAPTCHA site key**:
Set up Unity client: Fill in reCAPTCHA site key
## Build to WebGL > **IMPORTANT:** You need to build this sample to the root folder of the GitHub Pages repository. In Unity go to *File --> Build Settings*, select *Web* platform and choose ***Build***:
Build to WebGL
Find your GitHub Pages repository root folder and choose ***Select Folder***:
Build to WebGL: Select folder
After the build is completed, go to your GitHub Pages repository URL and you should see the *Sign in* panel:
Build to WebGL: Sign in panel
Open the browser console to check that reCAPTCHA V3 is loaded and ready:
Build to WebGL: reCAPTCHA ready
Click the ***Sign in*** button and after some authentication-related logs, the *Mint* panel should appear. In the console logs, we should see a positive reCAPTCHA verification score. Because we passed the reCAPTCHA verification, an Openfort player should have been created:
Build to WebGL: positive score
If you click the ***Mint*** button, the game will go through another reCAPTCHA verification. After a brief period, you should see the *NFT minted* panel with the Openfort player account address in a button:
Build to WebGL: NFT minted
Click on the ***Address*** button to open Etherscan and see that the transaction is confirmed:
Etherscan
## Code walkthrough All this is thanks to the [**``ReCaptcha.jslib plugin``**](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/main/unity-client/Assets/Plugins/WebGL/ReCaptcha.jslib) located in the Unity client, which allows the execution of reCAPTCHA V3 from the client. The ``.jslib`` methods are called from the [**``ReCaptchaController.cs``**](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/main/unity-client/Assets/Scripts/ReCaptchaController.cs). Then, when reCAPTCHA V3 gets the response token from the execution, we validate it in the backend through [**``VerifyReCaptcha.js``**](https://github.com/openfort-xyz/unity-recaptcha-sample/blob/main/ugs-backend/VerifyReCaptcha.js) ## Conclusion Upon completing the above steps, your Unity game will be fully integrated with Openfort and Google reCAPTCHA V3. Always remember to test every feature before deploying to guarantee a flawless player experience. ## Get support If you found a bug or want to suggest a new [feature/use case/sample], please [file an issue](https://github.com/openfort-xyz/unity-recaptcha-sample/issues). If you have questions, or comments, or need help with code, we're here to help: - on Twitter at https://twitter.com/openfortxyz - on Discord: https://discord.com/invite/t7x7hwkJF4 - by email: support+youtube@openfort.xyz export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/telegram-unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'Telegram-Unity', title: 'Integrate Unity WebGL on Telegram mini-app', description: 'Learn how you can integrate WebGL on Telegram mini-app', subtitle: 'Integrate Unity WebGL on Telegram mini-app', } ## Overview Use Unity WebGL to create a mini-game and integrate it into a Telegram mini-app. Building a new app? Check out the [Unity sample project](https://github.com/openfort-xyz/openfort-csharp-unity/tree/main/sample), a scene that demonstrates how to integrate Unity WebGL on Telegram mini-app. The scene is called `Telegram` and is located in the `Scenes` folder. ## Prerequisites Openfort SDK is set up in your Unity project. If not, follow the [quickstart guide](/docs/guides/unity/quickstart). This project uses WebGL, so make sure you also have [set up WebGL](/docs/guides/unity/webgl). ## Configuration ### Telegram mini-app setup + Create a Telegram bot and get the bot token. Follow the [official guide](https://core.telegram.org/bots#6-botfather) to create a bot and get the token. + [Configure your project providers](https://dashboard.openfort.xyz/players/auth/providers) Enable the Telegram provider and add the bot username and bot token.
Contract Info
Enable the Telegram (Mini-app) provider and add the bot token.
Contract Info
+ Import the [telegram mini app](https://www.jsdelivr.com/package/npm/@telegram-apps/sdk) SDK in your HTML template file. If you are using the Openfort SDK, you can add the script in the `index.html` file in Assets>WebGLTemplates>Openfort. ```html ``` This will expose a function `telegramApps.sdk.retrieveLaunchParams()` that will return the launch parameters from the Telegram mini-app. + Add a [Json library file](https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html) `Telegram.jslib`. This file will serve as a bridge between the Unity script and the Telegram SDK. ```csharp Telegram.jslib mergeInto(LibraryManager.library, { InitTelegramApp: function () { const telegramSDK = telegramApps.sdk; try { // Retrieve launch parameters from Telegram const launchParams = telegramSDK.retrieveLaunchParams(); var bufferSize = lengthBytesUTF8(launchParams.initDataRaw) + 1; var buffer = _malloc(bufferSize); stringToUTF8(launchParams.initDataRaw, buffer, bufferSize); return buffer } catch (error) { console.error('Error initializing app:', error); } return ""; }, }); ``` + Import the InitTelegramApp function in your Unity script. ```csharp Telegram.cs using System.Runtime.InteropServices; public class Telegram : MonoBehaviour { [DllImport("__Internal")] private static extern string InitTelegramApp(); void Start() { string initData = InitTelegramApp(); Debug.Log("Init data: " + initData); } } ``` + Authenticate with Telegram mini app token using the Openfort SDK. ```csharp Telegram.cs using System.Runtime.InteropServices; using Openfort.OpenfortSDK; public class Telegram : MonoBehaviour { [DllImport("__Internal")] private static extern string InitTelegramApp(); [SerializeField] string projectPublishableKey; [SerializeField] string shieldPublishableKey; [SerializeField] string shieldEncryptionShare; void Start() { openfort = await OpenfortSDK.Init( projectPublishableKey, shieldPublishableKey, shieldEncryptionShare ); string initData = InitTelegramApp(); Debug.Log("Init data: " + initData); ThirdPartyOAuthRequest request = new ThirdPartyOAuthRequest( ThirdPartyOAuthProvider.TelegramMiniApp, telegramAuth, TokenType.IdToken ); } } ``` Using Telegram mini-app as a third-party provider, your token is the Telegram mini-app initData. You can use this token to authenticate with the Openfort SDK. Using the Telegram mini-app as a third-party provider, `openfort.GetAccessToken()` is not available. Your access token is the Telegram mini-app initData. export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources/token-bound-accounts.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'token-bound-accounts', title: 'Use Token Bound Accounts', description: 'Learn how to use token bound accounts', subtitle: 'Learn how use token bound accounts (ERC6551) in your game.', } In this guide you'll find how to implement a token bound account based on a game character. This guide implements the backend code necessary to use token bound accounts in your game. It uses the [Openfort Node SDK](https://www.npmjs.com/package/@openfort/openfort-node). Architecture of the solution proposed in this guide:
using-token-bound-accounts
For a genereral overview of token bound accounts, see the [Token Bound Accounts](https://www.openfort.xyz/blog/technical-dive-combining-token-bound-account-tba-with-account-abstraction-aa) blog post. You can find the complete code of this guide in the [openfort samples GitHub](https://github.com/openfort-xyz/samples/tree/main/ERC6551-token-bound-accounts). ## Prerequisites When interacting with smart wallets through Openfort, import the contract and create a policy to sponsor gas. Get your secret key from the [Openfort dashboard](https://dashboard.openfort.xyz/developers/api-keys). ### 1. Import the NFT contract Token bound accounts are based on the ownership of a non-fungible token. In this guide, we'll use a contract, deployed at in [Polygon Amoy](https://mumbai.polygonscan.com/) at [0x380...AC0](https://mumbai.polygonscan.com/address/0xbed6a05ce8719bc00db1cc81a814192c82be1bb1). Add a new contract by clicking the `Add contract` button in the [Asset contracts](https://dashboard.openfort.xyz/assets) section, then enter: - The name of the contract (it can be any name you want; the name is only for identification purposes) - The network (`chainId`) where the smart contract is located: 80002. - The address of the contract. - Because the contract is verified in the block explorer, there's no need to provide an ABI manually.
DashboardAddContract
```bash command-line curl https://api.openfort.xyz/v1/contracts \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d name="SimpleNFT" \ -d address="0xbed6a05ce8719bc00db1cc81a814192c82be1bb1" \ -d chainId="80002" ``` ```ts server.ts const openfort = new Openfort(process.env.YOUR_SECRET_KEY); const SimpleNFT = await openfort.contracts.create({ name: "SimpleNFT", address: "0xbed6a05ce8719bc00db1cc81a814192c82be1bb1", chainId: chainId, }); ```
### 2. Set up gas sponsoring Add a new policy by clicking the `Add policy` button in the [Policies page](https://dashboard.openfort.xyz/policies), then enter: - The name of the policy (it can be any name you want; the name is only for identification purposes) - The network (`chainId`) where the smart contract is located: 80002. - As a fee sponsorship strategy, leave `pay gas for user`. - Under policy rules, create two rules: - 1st rule: - Leave `contract_functions` under Rule model. - Under Contract, select the contract you imported in the previous step. - Under Function name, select `All functions`. - 2nd rule: - Choose `account_functions` under Rule model.
GasPolicy
```bash command-line curl https://api.openfort.xyz/v1/policies \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d name="Trial sponsor" \ -d chainId="80002" \ -d "strategy[sponsorSchema]=pay_for_user" ``` Use the policy id to create policy rules and use the previously imported contract. ```bash command-line curl https://api.openfort.xyz/v1/policies/:id/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="contract_functions" \ -d functionName="All functions" \ -d contract="con_..." ``` ```bash command-line curl https://api.openfort.xyz/v1/policies/:id/policy_rules \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d type="account_functions" ``` ```ts server.ts const policy = await openfort.policies.create({ name: "test", chainId: 80002, strategy: { sponsorSchema: SponsorSchema.PayForUser, }, }); await openfort.policyRules.create({ contract: SimpleNFT.id, type: PolicySchema.ContractFunctions, policy: policy.id, functionName: "All functions", }); await openfort.policyRules.create({ type: PolicySchema.AccountFunctions, policy: policy.id, }); ```
## Create the character NFT As you know, to create a token bound account, you need to first know what NFT will be used to define the ownership of the account. Because in this guide we start from scratch, we'll also mint that NFT, but you could potentially use any NFT that you already own. If you want to use your own NFT, skip to the next section. We'll use a regular Openfort account to mint it. We start by creating an Openfort player and a regular Openfort account. ```ts server.ts const upgradeable_account = await openfort.accounts.create({ chainId: chainId, }); const player_upgradeable = upgradeable_account.player.id; ``` Then, we define the mint function interaction and create a `transactionIntent` using the gas sponsoring `policy` we created in the previous step. ```ts server.ts const interactionsMintOwnerNFT: Interaction[] = [ { contract: SimpleNFT.id, functionName: 'mint', functionArgs: [player_upgradeable.id], }, ] const transactionIntentSimpleNFT = await openfort.transactionIntents.create({ player: player_upgradeable.id, interactions: interactionsMintOwnerNFT, policy: policy.id, chainId: chainId, optimistic: false, }) ``` And we're all set! The character NFT is minted and owned by the `player_upgradeable`'s account. ## Create a token bound account Now that we have the NFT that will defined the ownership of the account, we can create a token bound account. Note that when creating the token bound account, we need to specify: - The `externalOwnerAddress` field: the address that currently owns the character NFT. - The `tokenContract` field: the address of the NFT contract. - The `tokenId` field: the token id of the character NFT. - The `accountType` field: specified that the account to be created is a token bound account. We start off by creating a new player and then assign a new counterfactual token bound account to it: ```ts server.ts const player_6551 = await openfort.players.create({ name: '6551 account', }) const account = await openfort.accounts.create({ player: player_6551.id, chainId: chainId, accountType: DataAccountTypes.Erc6551, tokenContract: SimpleNFT.id, tokenId: simpleOwnerNFTTokenId, externalOwnerAddress: upgradeable_account.address, }) ``` ## Transferring the character NFT You can send the character NFT to another account by calling the `safeTransferFrom` function of the NFT contract. This function takes the address of the current owner, the address of the new owner, and the token id as arguments. In this case, we'll transfer the character NFT to the previously `account` ownerAddress. This is because Openfort accounts come, by default, with a managed signer. Sending the NFT to the account ownerAddress allows a regular EOA to control the account. ```ts server.ts const interactionsExecCall: Interaction[] = [ { contract: SimpleNFT.id, functionName: 'approve', functionArgs: [ownerAddress, simpleOwnerNFTTokenId], }, { contract: SimpleNFT.id, functionName: 'safeTransferFrom', functionArgs: [ player_upgradeable.id, account.ownerAddress, simpleOwnerNFTTokenId, ], }, ] const transactionIntentTransferOwnerNFT = await openfort.transactionIntents.create({ player: player_upgradeable.id, interactions: interactionsExecCall, policy: policy.id, chainId: chainId, optimistic: false, }) ``` ## Minting an asset into the character NFT You can easily mint assets into the token bound account and even use it to mint assets. Here we interact with the same simple NFT contract to mint an NFT into the token bound account. ```ts server.ts const interactionsMintNFT: Interaction[] = [ { contract: SimpleNFT.id, functionName: 'mint', functionArgs: [player_6551.id], }, ] const transactionIntentSimpleNFT6551 = await openfort.transactionIntents.create( { player: player_6551.id, interactions: interactionsMintNFT, policy: policy.id, chainId: chainId, optimistic: false, } ) ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/smart-wallet/advanced/session-keys.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'session-keys', title: 'Using session keys', description: 'How to create a gaming session keys.', subtitle: 'Enhancing Play and Automating Actions with Customized Access Permissions', tocVideo: 'rh2E02PATlU', breadcrumb: 'Smart accounts', } In-game keys are specialized access tools assigned with specific in-game permissions, tailored for enhancing gaming experiences. Examples include: - A key that grants access only to specific game levels or areas. - A key that allows the use of up to 1000 in-game currency units. - A key that remains valid for 3 days before expiring. Moreover, these permissions can be combined to create more tailored experiences, such as a key that grants access to certain game levels, allows the spending of up to 1000 in-game currency units, and expires after 3 days. The potential applications for automated in-game actions are vast, including: - Automatic renewal of subscriptions or in-game passes. - Execution of predefined strategies or actions when certain in-game conditions are met. - Automatic management of in-game assets or resources, such as restocking supplies or managing in-game property. For a general overview of session keys, see the [Session keys](https://www.openfort.xyz/blog/technical-dive-session-keys) post. For more information about how to use the session key endpoints, you can visit our [API documentation](/docs/reference/api/create-a-session-key). ### API There are two types of session keys in Openfort: client session keys and server session keys. - **Client session keys** are created on the client side and are used to mint assets with a player's smart account. - **Server session keys** are created on the client by a key pair and send the address computed to the server. ## Configuration This section will guide you through the process of registering a session key and using it to mint an asset with a player's smart account. Check out our sample registering a session key with an account with a self-custodial signer: [GitHub source](https://github.com/openfort-xyz/openfort-js/tree/main/examples/apps/auth-sample). ### 1. Create a session key After you have authenticated your user with your regular authentication system, you can create a session key for them. To create a session key, you need to generate a key pair on the client-side and send the address computed from the public key to your server. Using one of the official Openfort [client libraries](/docs/libraries) everything is handled for you. 1. Install the client-side library: Open `Packages/manifest.json` and add these lines: ```json "com.openfort.sdk": "https://github.com/openfort-xyz/openfort-csharp-unity.git", "com.unity.nuget.newtonsoft-json": "3.0.1", "com.cysharp.unitask": "https://github.com/Cysharp/UniTask.git?path=src/UniTask/Assets/Plugins/UniTask#2.3.3" ``` 2. Initialize Openfort and create a session key: ```csharp client.cs using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class LoginSceneManager : MonoBehaviour { private OpenfortSDK openfort; private SessionKey sessionKey; private void Start() { openfort = await Openfort.Init("YOUR_OPENFORT_PUBLISHABLE_KEY"); sessionKey = openfort.ConfigureSessionKey(); } } ``` ### 1. Create a session key Using [ethers](https://www.npmjs.com/package/ethers), you can create a key pair on the server side of you application. ```ts const sessionKey = ethers.Wallet.createRandom(); ``` The parameter `sessionKey` contains the address that you will need to register. After creating the session key, you can go ahead and register it. ### 2. Register a session key - Server side Client side To register a session key, first send the address from the session key to your server. You can get the address from the session key object created above like this: ```csharp client.cs string address = sessionKey.Address; ``` Then, from your server you can make a request to the Openfort API or use one of our [server libraries](/docs/libraries) to register the session key. Install Openfort in your server-side and initialize it with your secret key. ```bash command-line npm install @openfort/openfort-node ``` Initialize '@openfort/openfort-node' with your secret key. ```ts server.ts import Openfort from '@openfort/openfort-node' const openfort = new Openfort('sk_test_...'); ``` ```bash command-line dotnet add package Openfort.SDK ``` Initialize 'Openfort.SDK' with your secret key. ```csharp server.cs using Openfort.SDK; using Openfort.SDK.Model; var openfort = new OpenfortClient("sk_test_..."); ``` The created session key would be valid since the 25th of May 2023 at 7:50 GMT (timestamp `1685001000`) and last for 1 hour (timestamp `1685001000`). For a useful resource to calculate timestamps online, visit [UNIX Timestamp](https://www.unixtimestamp.com/). Note how the `externalOwnerAddress` parameter is used to indicate the address of owner of the account that will be created under the specified player. It's only necessary to specify this parameter when the player is doesn't yet have an account in that chain. Also, note how a `policy` is used to indicate the policy that will be used to sponsor the gas fees of the transaction to register the session key. In this example `externalOwnerAddress` is used to indicate the address of the owner of the account that will be created under the specified player. Register the session key using Openfort: ```bash command-line curl https://api.openfort.xyz/v1/sessions \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d validUntil=1685004600 \ -d validAfter=0 \ -d externalOwnerAddress="0x41e6...9341" \ -d policy=pol_... ``` ```ts server.ts const sessionKeyAddress = '0x76e6...9341' const policyId = 'pol_...' const playerId = 'pla_...' const validUntil = 1685001000 const validAfter = 0 const chainId = 80002 const externalOwnerAddress = '0x41e6...9341' const playerSession = await openfort.sessions.create({ player: playerId, address: sessionKeyAddress, chainId: chainId, validUntil: validUntil, validAfter: validAfter, policy: policyId, externalOwnerAddress: externalOwnerAddress, }) ``` After registering the session key, you can see it in the dashboard under the player's page.
DashboardRegisterSessionKey
### 3. Sign the session key - Client side The owner of the account of the player needs then to authorize the new session key. To do so, it needs to sign the `userOperationHash` from the `nextAction` object returned by the API call to register the session key. `nextAction` response object from transaction_intents ```json "nextAction": { "type": "sign_with_wallet", "payload": { "signableHash": "0x91b4efe3648c79467f7b50aa9bb1b4eae383a52dd6d741d39ece29ed2ef8362d" } }, ``` Once the content of the `nextAction` parameter above is signed by the owner signer of the account, it has to be sent to Openfort using the endpoint `/v1/sessions/:id/signature` as shown below: Sign and send the session key registration: ```bash command-line curl https://api.openfort.xyz/v1/sessions/ses_.../signature \ -H "Authorization: Bearer $YOUR_PUBLISHABLE_KEY" \ -d signature="xyz..." ``` ```csharp client.cs await Openfort.SendSignatureSessionRequest( playerSession.id, SIGNED_USED_OP_HASH ); ``` ### 4. Using the session key - Server side Client side After the session key is registered, it can be used to authenticate requests from the player. Whenever you create a transaction intent from your backend, a signature will be needed from the session key or owner of the players' smart account. Create a transaction intent: ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d policy=pol_... ``` ```ts server.ts const playerId = 'pla_...' const policyId = 'pol_...' const contractId = 'con_...' const chainId = 80002 const optimistic = true const interaction: Interaction = { contract: contractId, functionName: 'mint', functionArgs: [playerId], } const transactionIntent = await openfort.transactionIntents.create({ player: playerId, chainId: chainId, optimistic: optimistic, interactions: [interaction], policy: policyId, }) ``` After creating the transaction intent, the session key will need to sign the nextAction `userOperationHash` and send it to Openfort. To do so, pass the `userOperationHash` to the `sendSignatureTransactionIntentRequest` method of the Openfort client library. Load session key and sign a transaction intent: ```csharp client.cs await Openfort.SendSignatureTransactionIntentRequest( collectResponseJSON.data.id, userOperationHash ); ``` ### 5. Revoke a session key - Client side Server side The owner of the account can always revoke the session key. To do so, it needs to sign the `userOperationHash` from the `nextAction` object returned by the API call to revoke the session key. Create a transaction intent: ```bash command-line curl https://api.openfort.xyz/v1/sessions/revoke \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player=pla_... \ -d address="0x76e6...9341" \ -d chainId=80002 \ -d policy=pol_... ``` ```ts server.ts const playerId = 'pla_...' const policyId = 'pol_...' const chainId = 80002 const sessionKeyAddress = '0x76e6...9341' const revokeSession = await openfort.sessions.revoke({ player: playerId, address: sessionKeyAddress, chainId: chainId, optimistic: true, policy: policyId, }) ``` Sign the transaction to revoke the session key and remove from client side: ```csharp client.cs var openfortTransactionResponse = await openfort.sendSignatureTransactionIntentRequest( revokeResponseJSON.data.id, userOperationHash ); ``` {/* Finish with a video. This also appears in the Sidebar via the "tocVideo" metadata */}
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/smart-wallet/connected-wallets.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'Using smart wallets', breadcrumb: 'Smart wallets', } Smart wallets in Openfort are your primary interface for blockchain interactions. Once an embedded signer is set up, a smart wallet is automatically created and associated for your user. There is no need to use the EIP1193 provider directly. Instead, use the Openfort SDK to interact with the smart wallet. ## Getting an EIP-1193 provider All of Openfort's wallets can export a standard [EIP-1193 provider](https://eips.ethereum.org/EIPS/eip-1193) object. This allows your app to request signatures and transactions from the wallet, using familiar JSON-RPC requests like `personal_sign` or `eth_sendTransaction`. To get a wallet's EIP-1193 provider, use the openfort `getEthereumProvider` method: ```csharp public class OpenfortManager : MonoBehaviour { private OpenfortSDK openfort; public async UniTask GetEthereumProvider(EthereumProviderRequest request) { return await GetOpenfortImpl().GetEthereumProvider(request); } } ``` export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/smart-wallet/send.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Requesting signatures and transactions', breadcrumb: 'Smart wallets', } To use smart wallets, you could use the EIP1193 provider or use a backend. This guide teaches how to make different requests to the smart wallet with the backend and Unity (it's easier to do so in the context of gaming because no need to encode transactions with Unity). ## Sign message To sign message with the smart wallet simply call the Openfort's `signMessage` or `signTypedData` method like so: ```csharp SignMessageRequest signMessageRequest = new SignMessageRequest("Hello World!"); string signature = await openfort.SignMessage(signMessageRequest); ``` ## Transactions ### 1. Create a transaction- Server side Create a request to your backend to create a transaction. In the body of the request: - Include the `player` that signs the transaction. - Include the `policy` that interacts with the contract for gas. If non-existent the user will need to have gas tokens. - Include `optimistic` if you want the transactions to be confirmed faster. Depending on the type of transaction you're creating you'll define `interactions`. The `interactions` field is an array of objects that contain the information of the contract to interact with, the function to call, and the arguments to pass to the function. - the interactions field contains the `contract` that has previously been added to Openfort. - the `functionName` defines the function to call from within the contract. - If there exist more than one function with the same name, the `functionArgs` will be used to determine which function to call. ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_..." \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][contract]"="con_..." \ -d "interactions[0][functionName]"="mint" \ -d "interactions[0][functionArgs][0]"="0x63B7...484f" ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const contractId = "con_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_mint = { contract: contractId, functionName: "mint", functionArgs: [playerId], }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_mint], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string contractId = "con_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionMint = new Interaction ( contract: contractId, functionName: "mint", functionArgs: new List { playerId } ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, optimistic: optimistic, interactions: new List { interactionMint } ); await client.TransactionIntents.Create(transactionIntentRequest); ``` Send the value of native tokens in the smallest denomination of the native currency i.e. wei (10^18) and as a `string`. The `to` parameter accepts: - any valid account `address` e.g. 0x680d2719F09B23F644c136Ab7336D42b6a76AdcC - a player `id` e.g. pla_... - an account `id` e.g. acc_... ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_..." \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][value]=1000" \ -d "interactions[0][to]=pla_..." ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_transfer = { value: "100", to: playerId }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_transfer], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionTransfer = new Interaction ( value: "100", to: playerId ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, externalOwnerAddress: null!, optimistic: optimistic, confirmationBlocks: 0, interactions: new List { interactionTransfer} ); await client.TransactionIntents.Create(transactionIntentRequest); ``` The `policy` used to sponsor a transaction that sends native tokens should have the `account_functions` policy rule. For a useful resource for computing the Wei, you can visit the [wei calculator](https://eth-converter.com/). Smart accounts support batching transactions, allowing multiple actions to be rolled into one. This feature significantly simplifies Web3 interactions for your users. For example, instead of executing `approve()` and then `transfer()`, your user can perform both in a single transaction. Batching transactions offers several key benefits: - Users only wait for one transaction to complete instead of multiple. - Users save on gas fees. - If any transaction in the batch fails, the entire batch reverts, preventing users from ending up in an inconsistent state. This characteristic is known as "atomicity." Fore security reasons, there is a limit of 9 interactions per transaction intent. To execute a batch transaction, you can send a transaction intent with **multiple interactions**, and each interaction will be executed in the order they are received. Openfort systems check the contract's ABI to find a function signature based on the `functionName` that you provide and the number of `functionArgs`. In the case that, in your contract, you have multiple functions with the same `functionName` and number of arguments, you can also include the `functionName` together with the argument types e.g. mint(address) ```bash command-line curl https://api.openfort.xyz/v1/transaction_intents \ -H "Authorization: Bearer $YOUR_SECRET_KEY" \ -d player="pla_...", \ -d policy="pol_..." \ -d chainId=80002 \ -d optimistic=true \ -d "interactions[0][contract]=con_..." \ -d "interactions[0][functionName]=mint" \ -d "interactions[0][functionArgs][0]=0x63B7...484f" \ -d "interactions[1][contract]=con_..." \ -d "interactions[1][functionName]=transfer" \ -d "interactions[1][functionArgs][0]=0x32B7...213d" ``` ```ts server.ts // Set your secret key. Remember to switch to your live secret key in production. // See your keys here: https://dashboard.openfort.xyz/developers/api-keys const Openfort = require('@openfort/openfort-node').default; const openfort = new Openfort(YOUR_SECRET_KEY); const playerId = "pla_..."; const contractId = "con_..."; const policyId = "pol_..."; const chainId = 80002; const optimistic = false; const interaction_mint = { contract: contractId, functionName: "mint", functionArgs: [playerId], }; const interaction_transfer = { contract: contractId, functionName: "transfer", functionArgs: [playerId], }; await openfort.transactionIntents.create({ "player":playerId, "chainId":chainId, "optimistic":optimistic, "interactions":[interaction_mint, interaction_transfer], "policy":policyId }); ``` ```csharp Program.cs string policyId = "pol_..."; string contractId = "con_..."; string playerId = "pla_..."; int chainId = 80002; bool optimistic = false; var interactionMint = new Interaction ( contract: contractId, functionName: "mint", functionArgs: new List { playerId } ); var interactionTransfer = new Interaction ( contract: contractId, functionName: "transfer", functionArgs: new List { playerId } ); var transactionIntentRequest = new CreateTransactionIntentRequest ( player: playerId, chainId: chainId, policy: policyId, externalOwnerAddress: null!, optimistic: optimistic, confirmationBlocks: 0, interactions: new List { interactionMint, interactionTransfer} ); await client.TransactionIntents.Create(transactionIntentRequest); ``` ### 2. Sign the transaction with the embedded signer. - Client side Use the `nextAction` returned by the backend to sign the transaction with the embedded signer. The transaction will be automatically signed and broadcasted by using the `sendSignatureTransactionIntentRequest` method. ```csharp private async void Mint() { // your backend that creates a mint request var webRequest = UnityWebRequest.Post("https://your-backend.com/api/mint", ""); webRequest.SetRequestHeader("Authorization", "Bearer " + AccessToken); webRequest.SetRequestHeader("Content-Type", "application/json"); webRequest.SetRequestHeader("Accept", "application/json"); await SendWebRequestAsync(webRequest); Debug.Log("Mint request sent"); if (webRequest.result != UnityWebRequest.Result.Success) { Debug.Log("Mint Failed: " + webRequest.error); return; } var responseText = webRequest.downloadHandler.text; Debug.Log("Mint Response: " + responseText); var responseJson = JsonConvert.DeserializeObject < RootObject > (responseText); var id = responseJson.Data.Id; if (responseJson.Data.NextAction == null) { Debug.Log("No Next Action"); return; } var nextAction = responseJson.Data.NextAction.Payload.UserOpHash; Debug.Log("Next Action: " + nextAction); // This example assumes you have already checked that Openfort 'embeddedState' is // `ready` and the user is `authenticated` var intentResponse = await Openfort.SendSignatureTransactionIntentRequest(id, nextAction); Debug.Log("Intent Response: " + intentResponse); } private Task SendWebRequestAsync(UnityWebRequest webRequest) { TaskCompletionSource < bool > tcs = new TaskCompletionSource < bool > (); webRequest.SendWebRequest().completed += _ => { switch (webRequest.result) { case UnityWebRequest.Result.Success: tcs.SetResult(true); break; default: tcs.SetException(new Exception(webRequest.error)); break; } }; return tcs.Task; } ``` ## Examples
{examples.map((x) => (
{x.description}
))}
export const examples = [ { name: 'Unity Sample Android', description: 'An integration with Google Play Games using Firebase Auth as a third party auth provider to create a non-custodial embedded signer.', href: 'https://github.com/openfort-xyz/sample-unity-firebaseauth-embedded-signer', }, { name: 'Unity Sample WebGL', description: 'An integration with Openfort Auth with non-custodial embedded signer.', href: 'https://github.com/openfort-xyz/sample-unity-webgl-embedded-signer', } ] export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/quickstart.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Quickstart: Unity Integration', subtitle: 'Get started with Openfort in your Unity project', } ## 1. Install the Openfort SDK ### Prerequisites The Unity SDK requires: - [UniTask](https://github.com/Cysharp/UniTask) package (version 2.3.3) - Installation of git-lfs from [git-lfs.github.com](https://git-lfs.github.com/) There are two ways to install the SDK: Since .dll files are stored on Git Large File Storage, you must download and install git-lfs from [here](https://git-lfs.github.com/). 1. Open the Package Manager 2. Click the add + button and select "Add package from git URL..." Enter https://github.com/openfort-xyz/openfort-csharp-unity.git?path=/src/Packages/OpenfortSDK and click 'Add' Since .dll files are stored on Git Large File Storage, you must download and install git-lfs from [here](https://git-lfs.github.com/). 1. Open your project's Packages/manifest.json file 2. Add "com.openfort.sdk": "https://github.com/openfort-xyz/openfort-csharp-unity.git?path=/src/Packages/OpenfortSDK" in the dependencies block ## 2. Set your auth providers 1. Navigate to the **auth providers** page on the [Openfort dashboard](https://dashboard.openfort.xyz) 2. Click Auth providers Methods in the side bar in the [players page](https://dashboard.openfort.xyz/players) 3. Configure the methods you want users to be able to login with ## 3. Get your [API keys](/docs/api-keys) In the [API keys](https://dashboard.openfort.xyz/developers/api-keys) section, you'll find: - **Publishable Key**: Safe to expose in client-side environment - **Secret Key**: Must be kept secure and used only server-side To generate non-custodial wallets: 1. Scroll to the Shield section and click **Create Shield keys** 2. **Store the encryption share** safely when it appears (you'll only see it once) 3. You'll receive: - **Shield Publishable Key**: Safe for client-side use - **Shield Secret Key**: Keep secure, server-side only ## 4. Initialize Openfort in your Unity project Create a new script to manage the Openfort integration: ```csharp using Openfort.OpenfortSDK; using Openfort.OpenfortSDK.Model; public class OpenfortManager: MonoBehaviour { private OpenfortSDK openfort; const string PublishableKey = "YOUR_OPENFORT_PUBLISHABLE_KEY"; const string ShieldApiKey = "YOUR_SHIELD_PUBLISHABLE_KEY"; const string ShieldEncryptionShare = "YOUR_SHIELD_ENC_SHARE"; private async void Start() { openfort = await OpenfortSDK.Init(PublishableKey, ShieldApiKey, ShieldEncryptionShare); } } ``` If you're developing for WebGL, check out the additional setup steps in the [Unity WebGL documentation](/docs/guides/unity/webgl). ## 5. You're ready to build! With Openfort configured in your Unity project, you can now: - [Implement user authentication](/docs/guides/unity/auth/email) - [Handle signatures](/docs/guides/unity/embedded-signer/sign-messages) For a complete example of Openfort integration in Unity, check out our [sample projects](https://github.com/openfort-xyz/openfort-csharp-unity/tree/main/samples). export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/resources.mdx --- import Layout from '@/layouts/DefaultLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Browse sample projects', description: 'Resources for getting started building with Openfort.', subtitle:'Discover resources and samples from Openfort', } Explore the library of sample projects using Openfort. Find even more samples in our [GitHub repository](https://github.com/openfort-xyz/samples#readme). ## Samples
{'Openfort Auth Sample in a Unity WebGL project.'} {'Template for integrating Openfort into a Android project.'} {'Unity sample with Openfort Auth and embedded signers.'}
## Backend
{'Template for integrating Openfort into a PlayFab backend.'} {'Template for integrating Openfort into a Firebase backend.'} {'Template for integrating Openfort into a UGS backend.'}
## Miscellaneous
{'Use In-App Purchase (IAP) to buy assets in your mobile game.'} {'Build Frames and make transactions onchain with Openfort.'} {'Discover how Lost Dungeon (Openfort game) is built.'}
Implemented your own library or an example you'd like to share? Send a link to your code to support@openfort.xyz and we'll be happy to add it to the list! export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/troubleshooting.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { title: 'Unity SDK Troubleshooting', description: 'The Openfort SDK for Unity helps you integrate your game.' } ## Platform and Compatibility ### Q: Can I test the SDK using the Unity Editor for Android and iOS? A: Yes, you can test the SDK using the Unity Editor for Android and iOS on both Mac and Windows. However, be aware that: - Native Android and iOS WebViews cannot run in the editor. - The macOS WebView is used for the Mac Unity Editor. - The Windows WebView is used for the Windows Unity Editor. For the most accurate testing, we recommend using an actual device or emulator. ### Q: Do you support IL2CPP for Windows? A: Currently, we do not support IL2CPP on the Windows platform. ### Q: I'm getting "Webview is not supported on this platform." How do I fix this? A: This error suggests that the WebView is not properly set up for your target platform. Ensure that you've correctly installed and configured the WebView plugin for your specific platform. If the issue persists, check our documentation for platform-specific setup instructions. ## Installation and Setup ### Q: I'm getting "The type or namespace name 'Shared' does not exist in the namespace 'VoltstroStudios.UnityWebBrowser' (are you missing an assembly reference?)". How do I fix this? A: This error often occurs when large files like `.dll` are not properly downloaded. To resolve this: 1. Download and install git-lfs from [https://git-lfs.com/](https://git-lfs.com/) 2. Clone the repository again or pull the latest changes. If the issue persists, ensure that all project dependencies are correctly installed and that your Unity version is compatible with the SDK. ## Authentication and Login ### Q: Can I log in using a WebView instead of opening the browser? A: The SDK primarily uses the system browser for authentication due to security considerations. However, if you have specific requirements for using a WebView, please contact our support team to discuss potential alternatives. ### Q: Why is the in-app browser used for login on mobile and not a WebView? A: The in-app browser is used for enhanced security, especially for single sign-on (SSO) purposes: - It runs on a separate process from the hosting game, preventing the game from accessing or modifying its content. - It's more resistant to malicious code injection. - WebViews, in contrast, can be more easily controlled by the hosting game, making them potentially less secure for authentication processes. ### Q: On iOS, when using AuthenticateWithOAuth login function, I get an alert asking: "[My Game] Wants to Use 'openfort.sdk' to Sign in". Can I modify or remove this alert? A: This alert is system-generated by iOS when using `ASWebAuthenticationSession` for secure authentication. Unfortunately, it cannot be removed or modified as it's triggered by the operating system. You can find more information about this in the [Apple Developer Documentation](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession). ## Functionality ### Q: Can I use the Unity SDK for crafting (burn and mint) assets? A: Yes, the SDK supports various blockchain operations, including minting and burning assets. For specific implementation details, please refer to our documentation on asset management or contact our support team for guidance. ## Troubleshooting ### Q: I'm getting "TimeoutException: Exceed Timeout:00:01:00". What does this mean? A: This exception occurs when a function call takes longer than the default timeout of one minute to return a response. To resolve this: 1. Check the bottom of the stack trace or logs to identify the specific function causing the timeout. 2. If needed, you can customize the timeout duration using the `SetCallTimeout` function. 3. Ensure your network connection is stable and that you're not experiencing unusually high latency. export const Page = ({ children }) => export default Page --- File: /pages/guides/unity/webgl.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { breadcrumb: 'Wallets', id: 'Unity', title: 'WebGL Setup', } Openfort's Unity SDK leverages an iframe to secure the key material for a user's embedded wallet. Given the use of an iframe, we recommend testing builds with Openfort's Unity SDK in the browser, or on a non-WebGL platform in the Unity editor. Watch this [demo](https://github.com/openfort-xyz/sample-unity-webgl-embedded-signer) of setting up the Openfort SDK in a Unity Project! To configure settings for your WebGL build to work with Openfort, go to your Project Settings in the Unity editor. Next, select Player and navigate to WebGL. Set the following values: - **In Resolution and Presentation**, select `openfort`.
unity-webgl-template
- In **Other Settings/Optimization, managed stripping level** to **minimal**
unity-stripping
export const Page = ({ children }) => export default Page --- File: /pages/guides/dashboard.mdx --- import Layout from '@/layouts/DefaultLayout' export const meta = { id: 'platform', title: 'Dashboard', description: 'Get up and running with SDKs, API keys, and integration tools.', subtitle: 'Get up and running with SDKs, API keys, and integration tools.', } **Use Openfort's [dashboard](https://dashboard.openfort.xyz) to manage your apps, retrieve your API keys, and manage the administrators for your account.** Openfort is a hosted platform which makes it very simple to get started without needing to manage any infrastructure. ## Guides
{'Use your ecosystem branding'} {'Invite others to collaborate and manage their permissions.'} {'Sponsor your users gas fees'}
export const Page = ({ children }) => export default Page --- File: /pages/guides/ecosystem.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { id: 'ecosystem', title: 'Ecosystem wallet', } Openfort **ecosystem wallets** is designed to help you create your ideal wallet and make it **interoperable across multiple games and applications**. With ecosystem you can move assets between different apps and can easily prove ownership of, sign messages, or send transactions. Check out the [live demo](https://rapidfire.sample.openfort.xyz/) of using an ecosystem wallet! Ecosystem wallets are _whitelabel_ and allow you to **own the entire developer experience**. In short, **you** own the _npm package_ the developer installs. ### Features | Feature | Status | |-------------------------------------------|--------| | Sign in with email | ✅ | | Sign in with OAuth | ✅ | | Sign in with Third-Party Auth | ✅ | | Embedded wallet creation | ✅ | | Embedded wallet recovery | ✅ | | Embedded wallet signatures & transactions | ✅ | | Embedded wallet key export | ✅ | | Native smart wallets | ✅ | | Gas sponsorship | ✅ | | Session keys | ✅ | | Social recovery | ✅ | ## Use cases Operating across multiple Openfort accounts is common practice for many projects. Consider the following scenarios: | SCENARIO | DESCRIPTION | |---|---| | **Token-based projects** | Create separate smart accounts for each project onboarded to use the same assets and tokens. | | **Ecosystem Wallet** | Create separate smart accounts for each independent project looking to use your wallet branding. | | **Ecosystem ID** | Manage wallets and identities, represented in the different games you control under a brand. | {/* ## Choose your Ecosystem type When using ecosystem you must onboard each independent project that signs up to use your authentication solution. | | STANDARD | CUSTOM | |---|---|---| | Integration effort | Lowest | Significantly higher | | Integration method | API or OAuth | API | | Onboarding | Openfort | Platform or Openfort | | User can access the Dashboard? | Yes, full Dashboard | No | | User support provided by | Platform and Openfort | Platform | | Automatic updates for new compliance requirements | Yes | No | | Ideal for platforms | With experienced online businesses as users | With significant engineering resources to dedicate to a fully white-labeled experience | */} {/* You can use Ecosystems to: - Gain a **holistic view** of your entire ecosystem includind players, transactions and any game you onboarded. - Manage **ecosystem parameters** like ecosystem assets, gas policies or player database in one single dashboard. - Offer a **unified login experience** for your ecosystem projects. - Incorporate **smart wallet** capabilities in your chain. */} ## Get started Check out these popular guides to get started.
{'Step by step guide to create your own ecosystem.'} {'Using ecosystem wallets with popular wallet connectors.'}
{/* ### Templates
Ecosystem JS is a open source package to create all-one ecosystems. Sampel on how to integrate custom auth within your ecosystem.
*/} export const Page = ({ children }) => export default Page --- File: /pages/guides/getting-started.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Quickstart', subtitle: 'Get started with Openfort libraries', } **The [Openfort JS SDK](https://www.npmjs.com/package/@openfort/openfort-js) is the easiest way to onboard your users onchain.** You will get out of the box support for: 1. Multiple login methods 2. Bare-meteal API access to customize your own UI 3. Non-custodial embedded signer 4. Account abtraction compatioble accounts and infrastructure Check out the [starter repos](/docs/guides/javascript/resources) for templates for integrating Openfort with various libaries, frameworks and use cases. ## 1. Install the Openfort SDK Install the latest version of the [Openfort JS SDK](https://www.npmjs.com/package/@openfort/openfort-js) using your package manager of choice: In order to integrate Openfort, you project must: - a **Node v20** (Active LTS version) or **higher**. - a [minimum TypeScript version of 5](https://github.com/microsoft/TypeScript/releases/tag/v5.0.2) ```sh Terminal npm install @openfort/openfort-js@latest ``` ```sh Terminal yarn add @openfort/openfort-js@latest ``` ```sh Terminal pnpm install @openfort/openfort-js@latest ``` ## 2. Set your auth providers Navigate to the **auth providers** page on the [Openfort dashboard](https://dashboard.openfort.xyz) by selecting your project and then clicking Auth providers Methods in the side bar in the [players page](https://dashboard.openfort.xyz/players). Select the account types you'd like users to be able to login with. For more information on how to enable social logins, check out the [dashboard docs](/docs/guides/dashboard/social-login). ## 3. Get your [API keys](/docs/api-keys) In the [API keys](https://dashboard.openfort.xyz/developers/api-keys) section, you'll find: - **Publishable Key**: Safe to expose in client-side environment - **Secret Key**: Must be kept secure and used only server-side To generate non-custodial wallets: 1. Scroll to the Shield section and click **Create Shield keys** 2. **Store the encryption share** safely when it appears (you'll only see it once) 3. You'll receive: - **Shield Publishable Key**: Safe for client-side use - **Shield Secret Key**: Keep secure, server-side only ## 4. Import Openfort into your app In your project, import the Openfort and configure it. Set the publishable keys fields to the publishable key you got from the Dashboard in step 3. Concretely, the Openfort SDK needs to be instantiated only once. ```ts server.ts import Openfort from "@openfort/openfort-js"; const openfort = new Openfort({ baseConfiguration: { publishableKey: "YOUR_OPENFORT_PUBLISHABLE_KEY", }, shieldConfiguration: { shieldPublishableKey: "YOUR_SHIELD_PUBLISHABLE_KEY", } }); ``` ## 5. You're good to go! Once you've configured your app, you can now use `openfort` throughout to access the Openfort SDK. Check out our [starter repo](https://github.com/openfort-xyz/openfort-js/tree/main/examples/apps/auth-sample) to see what a simple end-to-end integration looks like, or read on to learn how you can use Openfort to: - [Log your users in](/docs/guides/javascript/auth). - [Request signatures](/docs/guides/javascript/embedded-signer/sign-messages). export const Page = ({ children }) => export default Page --- File: /pages/guides/react-native.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Overview React Native', subtitle: 'Get started with React Native', } The [Openfort React Native SDK]() is a React Native library client for Openfort that allows you to add secure authentication, non-custodial embedded wallets, and powerful account abstraction into your application. ### Features | Feature | Status | |-------------------------------------------|--------| | Sign in with email | ✅ | | Sign in with OAuth | ✅ | | Sign in with wallets (SIWE) | ✅ | | Sign in with Third-Party Auth | ✅ | | Sign in with Farcaster (SIWF) | 🚧 | | Embedded wallet creation | ✅ | | Embedded wallet recovery | ✅ | | Embedded wallet signatures & transactions | ✅ | | Embedded wallet key export | ✅ | | Native smart wallets | ✅ | | Gas sponsorship | ✅ | | Session keys | ✅ | | Social recovery | ✅ | ## Get started Check out these popular guides to get started.
{'Setting up and importing a project'} {'Create an embedded wallet'}
## Templates Check out these popular samples to get started.
Check our React Native sample Integrate a mini-app with Telegram
export const Page = ({ children }) => export default Page --- File: /pages/guides/server.mdx --- import Layout from '@/layouts/DefaultLayout' export const meta = { id: 'platform', title: 'Using Openfort from your server ', description: 'Get up and running with SDKs, API keys, and integration tools.', subtitle: 'Get up and running with SDKs, API keys, and integration tools.', } Openfort's client-side SDKs, like `@openfort/openfort-js`, allow you to securely authenticate your users, connect their wallets, and create embedded wallets for them in your application frontend. In addition to these SDKs, you can also use **Openfort from your server** to secure and manage your application. See the guides below for some common flows. ## Get started
Create backend wallets for your application. Verify the authenticity of a user's access token. Generate wallets for users before they sign up.
## SDKs and API reference
NodeJS SDK for interacting with Openfort's infrastructure. C# SDK for interacting with Openfort's infrastructure. API reference for interacting with Openfort's infrastructure.
export const Page = ({ children }) => export default Page --- File: /pages/guides/unity.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Overview Unity', subtitle: 'Get started with Unity', } The [Openfort Unity SDK](https://github.com/openfort-xyz/openfort-csharp-unity) is a Unity library client for Openfort that allows you to add secure authentication, non-custodial embedded wallets, and powerful UX infrastructure into your game. ## Features | Feature | Status | |-------------------------------------------|--------| | Sign in with email | ✅ | | Sign in with OAuth | ✅ | | Sign in with guest mode | ✅ | | Sign in with Third-Party Auth | ✅ | | Embedded wallet creation | ✅ | | Embedded wallet recovery | ✅ | | Embedded wallet signatures & transactions | ✅ | | Native smart wallets | ✅ | | Gas sponsorship | ✅ | | Session keys | ✅ | | Compatible with Telegram mini-apps | ✅ | ## Supported platforms - Windows (64-bit) - macOS (minimum version 12.5) - Android (minimum version 5.1) - iOS (minimum version 15.2) - Unity 2021.3 or newer for Windows, macOS, Android and iOS - Unity 2019.4 or newer for macOS, Android, and iOS. Windows isn't supported on Unity versions from 2019.4 up through 2021.2. We have added compilation flags to the Unity SDK to ensure that specific Unity editors can only build certain platform targets. Please note that the table below indicates which editor you can use to build a platform target, but it does not determine whether you can run the SDK in that editor. For example, the SDK allows you to build iOS games using a macOS Unity Editor, but you cannot use the Windows Unity Editor. | Target Platform | Windows Unity Editor | macOS Unity Editor | |-----------------|:---------------------:|:-------------------:| | Windows | ✅ | ❌ | | macOS | ❌ | ✅ | | Android | ✅ | ✅ | | iOS | ❌ | ✅ | | Web | ✅ | ✅ | ## Get started Check out these popular guides to get started.
{'Setting up and importing a project'} {'Using embedded wallets with WebGL'} {'Create an embedded wallet'}
## Templates Check out these popular samples to get started.
Check our latest Unity sample Integrate a WebGL game with Telegram
export const Page = ({ children }) => export default Page --- File: /pages/guides/unreal-engine.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import Link from 'next/link' import { GlassPanel, IconPanel, Button, IconChevronRight, } from '@/components/ui' export const meta = { title: 'Overview Unreal Engine', subtitle: 'Get started with Unreal Engine', } The [Openfort Unreal Engine SDK]() is an Unreal Engine library client for Openfort that allows you to add secure authentication, non-custodial wallets, and powerful UX infrastructure into your game. ## Features | Feature | Status | |-------------------------------------------|--------| | Sign in with email | ✅ | | Sign in with OAuth | ✅ | | Sign in with Third-Party Auth | ✅ | | Embedded wallet creation | ✅ | | Embedded wallet recovery | ✅ | | Embedded wallet signatures & transactions | ✅ | | Native smart wallets | ✅ | | Gas sponsorship | ✅ | | Session keys | ✅ | ## Supported platforms - Windows (64-bit) - macOS (minimum version 10.5) - Android (minimum version 8.0) - iOS (minimum version 15.2) - Unreal Engine 5.4 - Unreal Engine 5.3 - Unreal Engine 5.2 - Unreal Engine 5.0 | Build Platform | Unreal Engine Version | Windows | MacOS | iOS | Android | |:--------------:|:---------------------:|---------|-------|-----|---------| | Windows | 5.0.3 | ✅ | ❌ | ❌ | ✅ | | | 5.2.1 | ✅ | ? | ? | ✅ | | | 5.3 | ❌ | ✅ | ✅ | ✅ | | | 5.4 | ❌ | ✅ | ✅ | ✅ | | macOS | 5.2.1 | ❌ | ✅ | ✅ | ✅ | | | 5.3 | ❌ | ✅ | ✅ | ✅ | | | 5.4 | ❌ | ✅ | ✅ | ✅ | ## Get started Check out these popular guides to get started.
{'Setting up and importing a project'} {'Create an embedded wallet'}
## Templates Check out these popular samples to get started.
Check our latest Unreal Engine sample
export const Page = ({ children }) => export default Page --- File: /pages/reference/api/[...slug].tsx --- import apiCommonSections from '@/../../spec/common-api-sections.json' assert { type: 'json' } import clientLibsCommonSections from '@/../../spec/common-client-libs-sections.json' assert { type: 'json' } import specFileTransformed from '@/../../spec/transforms/api_v0_openapi_deparsed.json' assert { type: 'json' } import specFile from '@/../../spec/openapi.yml' assert { type: 'yml' } import typeSpec from '@/../../spec/enrichments/tsdoc/combined_node.json' import RefSectionHandler from '@/components/reference/RefSectionHandler' import { flattenSections } from '@/lib/helpers' import handleRefGetStaticPaths from '@/lib/mdx/handleRefStaticPaths' import handleRefStaticProps from '@/lib/mdx/handleRefStaticProps' import { gen_v3 } from '@/lib/refGenerator/helpers' import type { TypeSpec } from '@/components/reference/Reference.types' import { useRouter } from 'next/router' import { useMemo, useState } from 'react' // @ts-ignore const specTransformed = gen_v3(specFileTransformed, 'wat', { apiUrl: 'apiv0' }) const sections = flattenSections(apiCommonSections) const sectionsNode = flattenSections(clientLibsCommonSections) const libraryPath = '/api' export type Language = 'bash' | 'ts' | 'csharp' export default function Config(props) { const router = useRouter() const [reqLanguage, setReqLanguage] = useState('bash') useMemo(() => { if (router.query.lang === 'ts') setReqLanguage('ts') if (router.query.lang === 'csharp') setReqLanguage('csharp') if (router.query.lang === 'bash') setReqLanguage('bash') }, [router.query.lang]) return ( ) } export async function getStaticProps() { return handleRefStaticProps(sections, libraryPath) } export async function getStaticPaths() { return handleRefGetStaticPaths(sections) } --- File: /pages/addresses.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { id: 'addresses', title: 'Entity Addresses', description: 'Check out the addresses used by Openfort', sidebar_label: 'Overview', } A list of contract addresses deployed by Openfort. ## Paymaster | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | [0x51032c841E823BB487C33c9f1773B18C8d0E5209](https://contractscan.xyz/contract/0x51032c841E823BB487C33c9f1773B18C8d0E5209) | | **Testnet Address** | [0x3210deD2e50363eF645C4eA15339Bec8Ac88e0F5](https://contractscan.xyz/contract/0x3210deD2e50363eF645C4eA15339Bec8Ac88e0F5) | ## Factories ### UpgradeableAccountFactory V6 | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | [0x5a2ed3e47798123ae30477424731de2ae47cc158](https://contractscan.xyz/contract/0x2fcb244d49f712c38109ba0bfc21433a4dd4452d) | ### UpgradeableAccountFactory V5 | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | [0x5a2ed3e47798123ae30477424731de2ae47cc158](https://contractscan.xyz/contract/0x5a2ed3e47798123ae30477424731de2ae47cc158) | | **Testnet Address** | [0xcb71e008b9062bb7abd558816f8135ef2cab576f](https://contractscan.xyz/contract/0xcb71e008b9062bb7abd558816f8135ef2cab576f) | ## Implementation ### UpgradeableAccountImplementation V5 | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | [0x6e4a235c5f72a1054abFeb24c7eE6b48AcDe90ab](https://contractscan.xyz/contract/0x6e4a235c5f72a1054abFeb24c7eE6b48AcDe90ab) | | **Testnet Address** | [0xc8ebbdd2da25906b96c374c9b1757b1421e9f45a](https://contractscan.xyz/contract/0xc8ebbdd2da25906b96c374c9b1757b1421e9f45a) | ### ERC6651AccountImplementation V1 | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | [0x528fe3cf9a857127eceb6df26ac7535839bfaef8](https://contractscan.xyz/contract/0xcb71e008b9062bb7abd558816f8135ef2cab576f) | | **Testnet Address** | [0x528fe3cf9a857127eceb6df26ac7535839bfaef8](https://contractscan.xyz/contract/0xcb71e008b9062bb7abd558816f8135ef2cab576f) | ## Forward contract | Chains | Address | | --------------------------- | ----------------------- | | **Mainnet Address** | 0xc82BbE41f2cF04e3a8efA18F7032BDD7f6d98a81 | | **Testnet Address** | 0xc82BbE41f2cF04e3a8efA18F7032BDD7f6d98a81 | | **Beam** | 0xd04f98c88ce1054c90022ee34d566b9237a1203c | export const Page = ({ children }) => export default Page --- File: /pages/api-keys.mdx --- import Layout from '@/layouts/DefaultGuideLayout' export const meta = { id: 'auth', title: 'API keys', breadcrumb: 'Configuration', } ## Livemode and testing Every account is divided into two universes: one for *testnet*, and one for *mainnet*. All requests exist in one of those two universes, and objects in one universe cannot be manipulated by objects in the other. In **test mode**, transactions can only go to **testnet networks**. ## API keys You'll need to authenticate your requests to access any of the endpoints in the Openfort API. In this guide, we'll look at how to get an API key. ### Project secret and publishable keys All accounts have a total of four API keys by default—two for test mode and two for live mode: 1. **Test project secret key:** Use this key to authenticate requests on your server when in test mode. By default, you can use this key to perform any API request without restriction. 2. **Test project publishable key:** Use this key for testing purposes in your web or mobile app’s client-side code. 3. **Live project secret key:** Use this key to authenticate requests on your server when in live mode. By default, you can use this key to perform any API request without restriction. 4. **Live project publishable key:** Use this key, when you’re ready to launch your app, in your web or mobile app’s client-side code. ### Shield secret and publishable keys All accounts have a total of three API keys by default—one for test mode and one for live mode: 1. **Shield secret key:** Use this key will allow you to store the recovery share of your users on server. 2. **Shield publishable key:** Use this key, when you’re ready to launch your app, in your web or mobile app’s client-side code. 3. **Shield encryption share key:** Only used whenever you're using the [automatic recovery](/docs/guides/javascript/embedded-signer/recovery) to encrypt the recovery share.
Type Value When to use
Secret On the server-side: Must be secret and stored securely in your web or mobile app’s server-side code (such as in an environment variable or credential management system) to call Openfort APIs. Don’t expose this key on a website or embed it in a mobile application.
Publishable On the client-side: Can be publicly-accessible in your web or mobile app’s client-side code (such as `openfort-js`).
## Reveal an API secret key in your dashboard Openfort APIs use your secret key to authenticate requests from your server. To find your API secret key for test mode: 1. Open the [API keys](https://dashboard.openfort.xyz/developers/api-keys) page. 2. Under `API keys`, in the `Secret key` row, click `Reveal test key` and save the value. export const Page = ({ children }) => export default Page --- File: /pages/chains.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Supported Chains', description: 'Openfort supported blockchains', } You can find a list of the chains that Openfort currently supports below. Openfort is compatible with all EVM chains. Don't see a chain you're interested in below? Get in touch, we'll make it available within 12 hours. | Blockchains | Testnet | Mainnet | |---------------------|-------------|-----------| | **Ancient8 Chain** | 28122024 | 888888888 | | **Arbitrum Nova** | | 42170 | | **Arbitrum One** | 421614 | 42161 | | **Avalanche** | 43113 | 43114 | | **B3** | 1993 | 8333 | | **Base** | 84532 | 8453 | | **Beam** | 13337 | 4337 | | **BNB** | 97 | 56 | | **Degen Chain** | | 666666666 | | **DOS Chain** | 3939 | 7979 | | **Gnosis** | 10200 | 100 | | **Immutable zkEVM** | 13473 | | | **Kroma** | 2358 | 255 | | **Linea** | 59140 | 59144 | | **Mantle** | 5001 | 5000 | | **Soneium** | 1946 | | | **OpBNB** | 5611 | 204 | | **Optimism** | 420 | 10 | | **Saakuru** | 247253 | 7225878 | | **Sophon** | 531050104 | | | **Polygon POS** | 80002 | 137 | | **Xai** | 37714555429 | 660279 | | **Zora** | 999999999 | 7777777 | | **ZKsync** | 300 | 324 | export const Page = ({ children }) => export default Page --- File: /pages/libraries.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { ServerLibraries } from '@/components/ServerLibraries' import { ClientLibraries } from '@/components/ClientLibraries' export const meta = { id: 'libraries', title: 'Openfort SDKs', description: 'Libraries and tools for interacting with your Openfort integration.', subtitle:'Libraries and tools for interacting with your Openfort integration.', } The recommended way to interact with the Openfort API is by using one of our official SDKs. export const Page = ({ children }) => export default Page --- File: /pages/security.mdx --- import Layout from '@/layouts/DefaultGuideLayout' import { IconCheck } from '@/components/ui' export const meta = { title: 'Security', description: 'Undertand how the security in Openfort.', } At Openfort, safeguarding the data and digital resources of your users is our utmost concern. We understand the crucial role we play in supporting our customers' applications and deeply value the trust placed in us. Our system's design and infrastructure have been rigorously evaluated through multiple security assessments, audits, and penetration tests. Recognizing security as an ever-evolving challenge, we continually subject our systems to these evaluations to identify and remedy emerging vulnerabilities. The process of embedding, maintaining, and testing security measures within your application is a significant endeavor. We dedicate ourselves to implementing industry-leading practices to protect your users' data and digital assets. Highlighted below are key practices we employ: ## Openfort authentication methods Openfort facilitates a variety of authentication techniques to confirm the identities of your users, including: - Email verification using a **one-time password (OTP)** and **password-based verification**. - **Social account** verification (Google, Apple, Twitter, Discord, Github) through OAuth2.0. - Ethereum wallet ownership verification using **Sign In With Ethereum (SIWE)**. ## Token Issuance Following identity verification via any method mentioned, Openfort grants tokens for session authentication within your app. - **App Access Token:** This token, helps ascertain user authentication within your app. It's a JSON Web Token (JWT), signed uniquely for your app, ensuring its authenticity and protection against forgery. This token helps your front and back end verify user authentication and originates from authenticated users. Its validity spans one hour, facilitating prompt session revocation and minimizing exposure risks. {/* ### Cookie Management When cookies are activated in your app via Openfort's dashboard, all tokens are securely set as HttpOnly cookies, enhancing defense against client-side vulnerabilities. These cookies are domain-specific, ensuring secure, scoped access. */} ## User data encryption and backup Openfort encrypts all database information at rest, with daily full snapshots and transaction log backups every five minutes, ensuring a week's worth of data restoration capabilities. ### Traffic encryption All network traffic employs TLS 1.2 encryption or higher, with HTTPS Strict Transport Security (HSTS). ### API security Access to Openfort's API for user data management requires authentication via the app's API secret. ## Signer configuration Based on client needs, we offer three types of signer setups: - **[Embedded non-custodial signer](/docs/security#embedded-non-custodial-signer)** **1. Embedded signer** - Creation and recreation of the private key occurs in a separate iframe within the **Openfort subdomain**. - Offers more flexibility for individual applications. - The user is custodian of the private keys. **2. Ecosystem signer** - Creation and recreation of the private key occurs in a separate iframe within the **ecosystem's subdomain**. - Offers interoperability at the ecosystem level granting apps and game with cross-app capabilities. - The user is custodian of the private keys. - **[Openfort custodial signer](/docs/security#openfort-custodial-signer)** - Reserved exclusively for **developer accounts**. Ideal for automatic transactions and internal transactions. - Openfort is custodian of the private keys. ## Embedded non-custodial signer Using Shamir Secret Sharing (SSS) technology, when a user creates an account, the private key is generated in an isolated iframe, which manages the user's private key and handles wallet operations. Here is how it works: 1. **Openfort API:** This component is responsible for storing metadata associated with a user's wallet, such as the wallet's address. It's a foundational layer that links a user's identity with their wallet operations securely. 2. **Isolated iframe:** A crucial element in ensuring the security and privacy of a user's private keys. The isolated iframe operates as a secure environment, managing the private key and executing wallet operations. This setup is pivotal because it keeps the private key confined to an in-memory state within the iframe, never storing it in a database or allowing it to persist beyond the session. This isolation also means the private key is protected from potential exposure or theft, as it's inaccessible to both the app's code and the Openfort SDK. 3. **Openfort SDK:** Offers a high-level interface for applications to interact with the embedded signer seamlessly. It simplifies the integration process, allowing developers to incorporate wallet functionalities without needing to delve into the complexities of blockchain technology. The design philosophy ensures that the wallet's private key is always under the user's control, aligning with the principles of **self-custody**. This means that neither Openfort nor any integrating application has access to the wallet's private keys, safeguarding user autonomy and security. The isolated iframe operates as a secure environment, managing the private key and executing wallet operations. If you'd like to host your own iframe instance, please refer to the [Advanced self-hosted documentation](/docs/guides/javascript/embedded-signer/advanced/iframe). ### Architecture
Non-custodial-key-generation
While the underlying key management and mechanics remain consistent across all setups, the hosting location of the iframe (ecosystem subdomain vs. within the app) determines whether the signer is cross-app or app-specific.
Ecosystem signer
### Key management Openfort's approach to key management and wallet recovery is built on a foundation of security and user control. When a user sets up an [embedded signer](/docs/guides/javascript/wallets), the process involves: - **Generating a Public-Private Keypair:** Utilizing a Cryptographically Secure Pseudorandom Number Generator (CSPRNG) to ensure randomness, the iframe generates a keypair. This process involves selecting 128 bits of entropy and converting them into a mnemonic using the BIP-39 standard, from which the public and private keys are derived. - **Private Key Splitting:** To enhance security, the private key is divided into three shares using Shamir's Secret Sharing, a method for distributing a secret amongst a group of participants. The shares are: - **A Device Share**, stored locally on the user's device within the iframe's storage. - **An Auth Share**, encrypted and held by Openfort, retrievable via the SDK during login. - **A Recovery Share**, encrypted with either user-provided entropy (like a strong password) or with automatic recovery. Recovery is facilitated through a service known as **Shield**, which manages the recovery share. It's important to note that the authentication share is retained within Openfort. **Deployment Options:** You can either use the [self-hosted](/docs/guides/javascript/embedded-signer/advanced/shield) or the [managed](/docs/guides/javascript/embedded-signer/recovery) Shield service. **Managed Shield service considerations** When Openfort manages Shield on your behalf, the primary security objective is to prevent Openfort from having control over both the authentication and recovery shares simultaneously. This precaution is essential to avoid the possibility of reconstructing the private key. To accomplish this, when registering your project with shield, you will get an extra parameter called `encryption_share`. This parameter is one of the 2 shares of a splitted encryption key (that uses the same Shamir's Secret Sharing algorithm) that is used to encrypt the recovery share. This way, Openfort can't decrypt the recovery share without the encryption share. This setup ensures that the full private key is reconstructed only in memory and never persists, requiring at least two of the three shares for reconstitution.
player-sign-flow
using-private-key
key-regeneration
### Account recovery Users are able to recover their private key even if they lose their device or if they lose access to your game. We support two methods of recoverability. **Offchain recoverability:** 1. If the user loses access to their device and is unable to retrieve their device share, they can combine their auth share and decrypt their recovery share to reconstitute the full private key. 2. If the user loses access to your app and is unable to retrieve their auth share, they can combine their device share and decrypt their recovery share to reconstitute the full private key.
wallet-recovery
**Onchain recoverability:** Using social recovery to update the owner of the smart account. You can choose to set up Openfort is the entrusted guardian uppon account initialization as well as set up guardians that you help your users can recover access to their smart account. Lear more [about social recovery](/docs/guides/javascript/smart-wallet/advanced/social-recovery).
Custodial-key-generation
## Openfort custodial signer [Backend wallets](/docs/guides/server/dev) are tailored for the internal mechanics of your game. The signer is stored with Openfort KMS in order to manage the operations of the game. Each account can serve several purposes like escrow assets, being used to deploy contracts or simply as a treasury to transfer purchases of NFTs. The backend wallets are ERC2771 compatible to offer gasless transactions. ### Architecture For developers and studios requiring managed wallets, Openfort leverages Google Cloud KMS to generate and securely store wallet private keys. This process allows for the automated creation of developer wallets, streamlining the management of in-game currencies, assets, and player transactions.
Custodial-key-generation
### Key Management The KMS ensures that all cryptographic keys are stored securely, with stringent access controls and audit trails. This setup not only provides a high level of security but also complies with industry standards and regulatory requirements, ensuring that sensitive information is protected against unauthorized access. The use of a KMS allows for robust key management and **recovery processes**. In the event of key loss or compromise, the KMS provides mechanisms for key recovery and rotation, minimizing the risk of asset loss and ensuring continuity of game operations. ## Smart Contract Accounts Openfort [smart accounts](https://github.com/openfort-xyz/openfort-contracts) offer programmability directly at the wallet level. Custodianship of these smart accounts depends uppon how the signer that "owns" the wallet is managed. ## Third-Party Reviews All of Openfort’s cryptographic libraries (notably around Shamir's Secret Sharing) are [open-sourced](https://github.com/openfort-xyz/shamir-secret-sharing-go) and have undergone an [audit](https://drive.google.com/file/d/1fQ5lCg-JgH_TcSt9hCwcIv-psP_8Nbze/view?usp=sharing). The latest smart contracts and paymasters were also [audited](https://drive.google.com/drive/folders/1aoPgJD_oz1qagWflnO91ASlQo-2upjRL?usp=sharing). If you are a security researcher and would like to reach out to us, please do so using security@openfort.xyz. export const Page = ({ children }) => export default Page