Skip to content

Commit

Permalink
Token Verify Endpoint (#44)
Browse files Browse the repository at this point in the history
* impl `/oauth/verify-token`

* fix
  • Loading branch information
a01sa01to authored Nov 14, 2024
1 parent f843414 commit c117e18
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 0 deletions.
2 changes: 2 additions & 0 deletions webapp/api/oauth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { HonoEnv } from '../../load-context'
import oauthAccesstokenRoute from './accessToken'
import oauthAuthorizeRoute from './authorize'
import oauthCallbackRoute from './callback'
import oauthVerifytokenRoute from './verifyToken'

const app = new Hono<HonoEnv>()

app.route('/authorize', oauthAuthorizeRoute)
app.route('/callback', oauthCallbackRoute)
app.route('/access-token', oauthAccesstokenRoute)
app.route('/verify-token', oauthVerifytokenRoute)

export default app
97 changes: 97 additions & 0 deletions webapp/api/oauth/verifyToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { zValidator } from '@hono/zod-validator'
import { Hono } from 'hono'
import { HonoEnv } from 'load-context'
import { z } from 'zod'

const app = new Hono<HonoEnv>()

// 仕様はここ参照: https://github.com/saitamau-maximum/auth/issues/43

interface ValidResponseType {
valid: true
client: {
id: string
name: string
description: string | null
logo_url: string | null
owner_id: string
}
user_id: string
expires_at: number
scopes: string[]
}

interface InvalidResponseType {
valid: false
client: null
user_id: null
expires_at: null
scopes: null
}

const INVALID_REQUEST_RESPONSE: InvalidResponseType = {
valid: false,
client: null,
user_id: null,
expires_at: null,
scopes: null,
}

app.post(
'/',
zValidator(
'form',
z.object({
access_token: z.string(),
}),
async (res, c) => {
if (!res.success)
return c.json<InvalidResponseType>(INVALID_REQUEST_RESPONSE, 400)
},
),
async c => {
const { access_token } = c.req.valid('form')

const nowUnixMs = Date.now()
const nowDate = new Date(nowUnixMs)

const tokenInfo = await c.var.dbClient.query.token.findFirst({
where: (token, { eq, and, gt }) =>
and(
eq(token.access_token, access_token),
gt(token.code_expires_at, nowDate),
),
with: {
client: true,
scopes: {
with: {
scope: true,
},
},
},
})

c.header('Cache-Control', 'no-store')
c.header('Pragma', 'no-cache')

// Token が見つからない場合
if (!tokenInfo) {
return c.json<InvalidResponseType>(INVALID_REQUEST_RESPONSE, 404)
}

return c.json<ValidResponseType>({
valid: true,
client: tokenInfo.client,
user_id: tokenInfo.user_id,
expires_at: tokenInfo.access_token_expires_at.getTime(),
scopes: tokenInfo.scopes.map(s => s.scope.name),
})
},
)

// POST 以外は許容しない
app.all('/', async c => {
return c.text('method not allowed', 405)
})

export default app

0 comments on commit c117e18

Please sign in to comment.