Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24.12.0
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@

mainブランチの最新のコードで動作している<a href="https://main.d3s7y579k91bnt.amplifyapp.com/" target="_blank" rel="noopener noreferrer">デモ</a>を公開しています。

## 推奨動作環境
## 確認済動作環境

- Node.js: v18.16.0
- yarn: 1.22.19
- Node.js: v24.12.0
- yarn: 1.22.22
- 推奨ブラウザ: Chrome

## セットアップと実行
Expand Down
2 changes: 1 addition & 1 deletion components/UserIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useState } from 'react';
import { useRouter } from 'next/router';
import { signOut } from 'next-auth/client';
import { signOut } from 'next-auth/react';
import styled from 'styled-components';

type IconProps = {
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "sippo-vroidsdk-test2",
"name": "vroid-hub-api-example",
"version": "0.1.0",
"private": true,
"scripts": {
Expand All @@ -22,14 +22,18 @@
"@types/three": "^0.153.0",
"eslint": "^8.42.0",
"eslint-config-next": "13.4.4",
"jsonwebtoken": "^9.0.2",
"jwa": "^1.4.2",
"jws": "^3.2.2",
"next": "13.4.4",
"next-auth": "3",
"next-auth": "4.24.13",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-use": "^17.4.0",
"styled-components": "^6.0.5",
"three": "^0.154.0",
"typescript": "^5.1.6"
"typescript": "^5.1.6",
"yarn": "^1.22.22"
},
"lint-staged": {
"*.{ts,tsx}": [
Expand Down
6 changes: 3 additions & 3 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Provider } from 'next-auth/client';
import { SessionProvider } from 'next-auth/react';
import { ThemeProvider, createGlobalStyle } from 'styled-components';
import { light } from '@charcoal-ui/theme';
import { CharcoalProvider, OverlayProvider, SSRProvider } from '@charcoal-ui/react';
Expand All @@ -14,7 +14,7 @@ export default function App({ Component, pageProps }) {
<meta property="og:title" content="VRoid Hub API Example" />
<meta property="og:description" content="Simple example of VRoid Hub API" />
</Head>
<Provider session={pageProps.session}>
<SessionProvider session={pageProps.session}>
<SSRProvider>
<CharcoalProvider themeMap={{ ':root': light }}>
<OverlayProvider>
Expand All @@ -25,7 +25,7 @@ export default function App({ Component, pageProps }) {
</OverlayProvider>
</CharcoalProvider>
</SSRProvider>
</Provider>
</SessionProvider>
</>
);
}
Expand Down
80 changes: 51 additions & 29 deletions pages/api/auth/[...nextauth].ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,56 @@
import NextAuth, { Account, Profile, User } from 'next-auth';
import NextAuth from 'next-auth';

export default NextAuth({
providers: [
{
// The name to display on the sign in form (e.g. 'Sign in with...')
id: 'vroid',
name: 'VRoidHub',
type: 'oauth',
version: '2.0',
scope: 'default',
protection: ['state', 'pkce'],
params: { grant_type: 'authorization_code' },
accessTokenUrl: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/oauth/token`,
requestTokenUrl: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/oauth/token`,
authorizationUrl: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/authorize/confirm?response_type=code`,
profileUrl: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/api/account`,
headers: {
'X-Api-Version': 11,
type: 'oauth',
authorization: {
url: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/authorize/confirm?response_type=code`,
params: { scope: 'default' }
},
token: {
// v4でheadersを付与する場合独自拡張が必要になった https://next-auth.js.org/configuration/providers/oauth#token-option
url: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/oauth/token`,
params: { grant_type: 'authorization_code' },
async request({ params, client, checks }) {
const response = await fetch(
`${process.env.NEXT_PUBLIC_VROID_HUB_URL}/oauth/token`, {
headers: {
'X-Api-Version': '11' // VRoidHubAPI独自
},
method: 'POST',
body: new URLSearchParams({
...params,
client_id: client.client_id as string,
client_secret: client.client_secret as string,
grant_type: 'authorization_code',
code_verifier: checks.code_verifier as string,
redirect_uri: client.redirect_uris[0],
})
},
)

return { tokens: await response.json() };
}
},
userinfo: {
url: `${process.env.NEXT_PUBLIC_VROID_HUB_URL}/api/account`,
async request({ tokens }) {
const response = await fetch(`${process.env.NEXT_PUBLIC_VROID_HUB_URL}/api/account`, {
headers: {
'Authorization': `${tokens.token_type} ${tokens.access_token}`,
'X-Api-Version': '11', // VRoidHubAPI独自
}
});

return await response.json();
},
},
async profile(profile: any, tokens) {
// You can use the tokens, in case you want to fetch more profile information
// For example several OAuth providers do not return email by default.
// Depending on your provider, will have tokens like `access_token`, `id_token` and or `refresh_token`
checks: ['pkce', 'state'],
async profile(profile: any) {
return {
id: profile.data.user_detail.user.id,
name: profile.data.user_detail.user.name,
Expand All @@ -32,25 +61,18 @@ export default NextAuth({
clientSecret: process.env.CLIENT_SECRET,
},
],
secret: process.env.NEXT_PUBLIC_NEXTAUTH_SECRET,
callbacks: {
async jwt(token, user, account, profile, isNewUser) {
if (account?.accessToken) {
token.accessToken = account.access_token;
}
if (profile) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: JWTのtoken.idへの代入が消されていますが、これは不要になったのでしょうか?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.logで値を見ていたのですが、元からprofileにidは入っていなさそうだったので消しました。おそらく最初に実装していた際に、NextAuthのサンプルコードなどを参考にしていたのではないでしょうか?

ちなみにprofileに入りうるのは { data : CurrentUserSerializer, ... } のようなデータです

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

承知しました。確認ありがとうございます

token.id = profile.id;
async jwt({ token, account }) {
if (account?.access_token) {
token.accessToken = account?.access_token;
}

return token;
},

async session(session, token) {
async session({ session, token }) {
session.accessToken = token.accessToken;
return session;
},

async signIn(user: User, account: Account, profile: Profile) {
return true;
},
},
}
});
4 changes: 2 additions & 2 deletions pages/api/vroid/models/account.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSession } from 'next-auth/client';
import { getSession } from 'next-auth/react';
import type { CharacterModelCollectionResponse, CharacterModelSerializer } from '@/types/Response';
import { NextApiRequest, NextApiResponse } from 'next';
import { vroidHubApi } from '@/lib/vroid-hub-api';
Expand Down Expand Up @@ -36,4 +36,4 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
resJson.data = apiResJson.data;

return res.status(200).json(resJson);
}
}
4 changes: 2 additions & 2 deletions pages/api/vroid/models/hearts.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getSession } from 'next-auth/client';
import type { CharacterModelCollectionResponse, CharacterModelSerializer } from '@/types/Response';
import { getSession } from 'next-auth/react';
import { CharacterModelCollectionResponse, CharacterModelSerializer } from '../../../../types/Response';
import { NextApiRequest, NextApiResponse } from 'next';
import { vroidHubApi } from '@/lib/vroid-hub-api';

Expand Down
2 changes: 1 addition & 1 deletion pages/api/vroid/models/staff_picks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getSession } from 'next-auth/client';
import type { CharacterModelSerializer, HeartCollectionResponse } from '@/types/Response';
import { getSession } from 'next-auth/react';
import { NextApiRequest, NextApiResponse } from 'next';
import { vroidHubApi } from '@/lib/vroid-hub-api';

Expand Down
2 changes: 1 addition & 1 deletion pages/api/vroid/vrm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSession } from 'next-auth/client';
import { getSession } from 'next-auth/react';
import type { NextApiRequest, NextApiResponse } from 'next';
import { fetchVRMModel } from '../../../lib/vroid-hub-api';

Expand Down
5 changes: 3 additions & 2 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { signIn, useSession } from 'next-auth/client';
import { signIn, useSession } from 'next-auth/react';

import React, { useCallback, useState } from 'react';
import { useAsync } from 'react-use';
import { useRouter } from 'next/router';
Expand All @@ -15,7 +16,7 @@ type ModelsListState = {
};

export default function Index() {
const [session] = useSession();
const { data: session } = useSession()
const router = useRouter();

// ユーザーが保持しているモデルの一覧
Expand Down
31 changes: 30 additions & 1 deletion types/next-auth.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
import NextAuth from 'next-auth';
import { DefaultSession } from "next-auth";
import { JWT } from "next-auth/jwt";

declare module "next-auth" {
interface Session {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: この辺りの各種interfaceはどこで利用しているものでしょうか?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

使っているのはpages/api/auth/[...nextauth].tsですね。この辺入れておかないと形エラーになってしまうので入れた気がします

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO: 分かりました。declare module "next-auth" が1つのファイルに複数あるメリットはないと思うので、まとめていただけるとありがたいです。

accessToken?: string;
}
}

declare module "next-auth" {
interface OAuthConfig {
scope?: string;
params: {
grant_type: 'string'
}
}
}

declare module "next-auth" {
interface Profile {
id?: string;
scope?: string;
}
}

declare module "next-auth/jwt" {
interface JWT {
accessToken?: string;
}
}

declare module 'next-auth' {}
Loading