Skip to content

Commit

Permalink
[relay, auth-kit, auth-client] feat: support redirectUrl (#157)
Browse files Browse the repository at this point in the history
## Motivation

Allow mobile apps using the connect flow to instruct wallet clients to
return the user back to the app after signing.

## Change Summary

- support redirectUrl when initiating a sign in
- remove ethers as a hard dependency from auth-client
- add an expo example application

## Merge Checklist

_Choose all relevant options below by adding an `x` now or at any time
before submitting for review_

- [x] PR title adheres to the [conventional
commits](https://www.conventionalcommits.org/en/v1.0.0/) standard
- [x] PR has a changeset
- [x] PR has been tagged with a change label(s) (i.e. documentation,
feature, bugfix, or chore)
- [x] PR includes documentation if necessary
- [x] All commits have been signed

## Additional Context

If this is a relatively large or complex change, provide more details
here that will help reviewers
  • Loading branch information
deodad authored Apr 17, 2024
1 parent 1265f28 commit 62874a0
Show file tree
Hide file tree
Showing 44 changed files with 15,042 additions and 1,238 deletions.
11 changes: 11 additions & 0 deletions .changeset/slimy-socks-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"with-next-auth": patch
"frontend-only": patch
"@farcaster/auth-client": patch
"@farcaster/auth-kit": patch
"client-test": patch
"@farcaster/auth-relay": patch
---

- support redirectUrl
- remove ethers hard dependency
1 change: 1 addition & 0 deletions apps/relay/src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type CreateChannelRequest = {
notBefore?: string;
expirationTime?: string;
requestId?: string;
redirectUrl?: string;
};

export type AuthenticateRequest = {
Expand Down
3 changes: 3 additions & 0 deletions apps/relay/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export const createChannelRequestSchema = {
requestId: {
type: "string",
},
redirectUrl: {
type: "string",
},
},
required: ["siweUri", "domain"],
additionalProperties: false,
Expand Down
3 changes: 3 additions & 0 deletions apps/relay/src/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,14 @@ describe("relay server", () => {
const notBefore = "2023-01-01T00:00:00Z";
const expirationTime = "2023-12-31T00:00:00Z";
const requestId = "some-request-id";
const redirectUrl = "http://some-redirect-url";
const response = await http.post(getFullUrl("/v1/channel"), {
...channelParams,
nonce: customNonce,
notBefore,
expirationTime,
requestId,
redirectUrl,
});

expect(response.status).toBe(201);
Expand All @@ -103,6 +105,7 @@ describe("relay server", () => {
expect(params.get("notBefore")).toBe(notBefore);
expect(params.get("expirationTime")).toBe(expirationTime);
expect(params.get("requestId")).toBe(requestId);
expect(params.get("redirectUrl")).toBe(redirectUrl);
expect(channelToken).toMatch(/[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}/);
expect(nonce).toBe(customNonce);
expect(url).toBe(connectUri);
Expand Down
4 changes: 2 additions & 2 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"indentSize": 2,
"indentStyle": "space",
"lineWidth": 120,
"ignore": []
"ignore": ["examples"]
},
"linter": {
"enabled": true,
Expand All @@ -18,6 +18,6 @@
"useLiteralKeys": "off"
}
},
"ignore": []
"ignore": ["examples"]
}
}
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ services:
command: --save 1 1 --loglevel warning --maxmemory-policy noeviction
volumes:
- redis-data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD-SHELL", "redis-cli", "ping"]
interval: 10s
Expand Down
35 changes: 35 additions & 0 deletions examples/authkit-expo-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files

# dependencies
node_modules/

# Expo
.expo/
dist/
web-build/

# Native
*.orig.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision

# Metro
.metro-health-check*

# debug
npm-debug.*
yarn-debug.*
yarn-error.*

# macOS
.DS_Store
*.pem

# local env files
.env*.local

# typescript
*.tsbuildinfo
81 changes: 81 additions & 0 deletions examples/authkit-expo-demo/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// polyfill TextEncoder
import 'fastestsmallesttextencoderdecoder';

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, Button, Linking } from 'react-native';
import { AuthKitProvider, useSignIn } from '@farcaster/auth-kit';
import { useEffect, useCallback } from 'react';

const config = {
rpcUrl: 'https://mainnet.optimism.io',
domain: 'example.com',
siweUri: 'https://example.com/login',
relay: 'http://localhost:8000',
redirectUrl: 'exp://192.168.0.168:8081',
};

export default function App() {
return (
<AuthKitProvider config={config}>
<Content />
<StatusBar style="auto" />
</AuthKitProvider>
);
}

function Content() {
const {
signIn,
url,
isError,
isSuccess,
connect,
reconnect,
channelToken,
data,
validSignature
} = useSignIn();

const onClick = useCallback(() => {
if (isError) {
reconnect();
}
signIn();

if (url) {
Linking.openURL(url);
}
}, [isError, reconnect, signIn, url]);

useEffect(() => {
if (!channelToken) {
connect();
}
}, [channelToken, connect]);

const authenticated = isSuccess && validSignature;

return (
<View style={styles.container}>
{authenticated ?
<View>
<Text>Signed in!</Text>
<Text>{data?.username}</Text>
</View> :
<View>
<Button onPress={onClick} title="Sign in">Sign in</Button>
</View>
}
<StatusBar style="auto" />
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
30 changes: 30 additions & 0 deletions examples/authkit-expo-demo/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"expo": {
"name": "AuthKitExpoDemo",
"slug": "AuthKitExpoDemo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/authkit-expo-demo/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/authkit-expo-demo/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/authkit-expo-demo/assets/splash.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions examples/authkit-expo-demo/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
8 changes: 8 additions & 0 deletions examples/authkit-expo-demo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { registerRootComponent } from 'expo';

import App from './App';

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);
20 changes: 20 additions & 0 deletions examples/authkit-expo-demo/metro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');

// Find the project and workspace directories
const projectRoot = __dirname;
// This can be replaced with `find-yarn-workspace-root`
const monorepoRoot = path.resolve(projectRoot, '../..');

const config = getDefaultConfig(projectRoot);

// 1. Watch all files within the monorepo
config.watchFolders = [monorepoRoot];
// 2. Let Metro know where to resolve packages and in what order
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, 'node_modules'),
path.resolve(monorepoRoot, 'node_modules'),
];

module.exports = config;

27 changes: 27 additions & 0 deletions examples/authkit-expo-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "authkit-expo-demo",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web"
},
"dependencies": {
"@expo/metro-runtime": "~3.1.3",
"@farcaster/auth-kit": "*",
"expo": "~50.0.14",
"expo-status-bar": "~1.11.1",
"fastestsmallesttextencoderdecoder": "^1.0.22",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-native": "0.73.6",
"react-native-web": "~0.19.6",
"viem": "^2.9.20"
},
"devDependencies": {
"@babel/core": "^7.20.0"
},
"private": true
}
4 changes: 4 additions & 0 deletions examples/authkit-expo-demo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"compilerOptions": {},
"extends": "expo/tsconfig.base"
}
Loading

0 comments on commit 62874a0

Please sign in to comment.