honojs-middleware/packages/oauth-providers/src/providers/twitch/authFlow.ts

132 lines
3.2 KiB
TypeScript
Raw Normal View History

feat(oauth-providers): Add Twitch OAuth Provider (#981) * feat(twitch): Add type definitions for Twitch OAuth scopes * feat(twitch): Add additional type definitions for Twitch moderator scopes * feat(twitch): Add IRC and PubSub-specific chat scopes to types * feat(twitch): Add new type definitions for Twitch API responses * feat(twitch): Add new user-related scopes for Twitch API * feat(twitch): Add type definitions and import paths for Twitch provider * feat(twitch): Implement Twitch OAuth handlers and response types for mock api * feat(twitch): Add revokeToken function to handle OAuth token revocation * feat(twitch): Add Twitch OAuth middleware mocks and tests * feat(twitch): Implement Twitch OAuth authentication flow and user data retrieval * feat(twitch): Add custom state handling for Twitch OAuth middleware * docs(twitch): Update README with Twitch OAuth integration details * docs: Update Twitch API reference link for scopes in README * fix(twitch): Remove error handling for error_description in auth flow * refactor(twitch): Update token handling and response types for refresh and revoke * feat(twitch): Add token validation function for Twitch OAuth * feat(twitch): Add token validation handler and update response types * docs: Add token validation section to README for Twitch integration * chore(oauth-providers): changesets summary * fix(twitch): make redirect_uri optional in twitchAuth options * refactor(twitch): clean up commented code and improve test assertions * refactor(twitch): improve type assertions for JSON responses * refactor(twitch): update type assertion for JSON response handling * semver amendment Changed version from patch to minor * docs: update README with token validation instructions for Twitch --------- Co-authored-by: Younis-Ahmed <23105954+jonaahmed@users.noreply.github.com>
2025-03-12 16:55:47 +08:00
import { HTTPException } from 'hono/http-exception'
import type { Token } from '../../types'
import { toQueryParams } from '../../utils/objectToQuery'
import type {
TwitchErrorResponse,
TwitchUserResponse,
TwitchTokenResponse,
TwitchUser,
Scopes,
} from './types'
type TwitchAuthFlow = {
client_id: string
client_secret: string
redirect_uri: string
scope: Scopes[]
state: string
code: string | undefined
force_verify: boolean | undefined
}
export class AuthFlow {
client_id: string
client_secret: string
redirect_uri: string
scope: string
state: string
code: string | undefined
token: Token | undefined
refresh_token: Token | undefined
granted_scopes: string[] | undefined
user: Partial<TwitchUser> | undefined
force_verify: boolean | undefined
constructor({
client_id,
client_secret,
redirect_uri,
scope,
state,
code,
force_verify,
}: TwitchAuthFlow) {
this.client_id = client_id
this.client_secret = client_secret
this.redirect_uri = redirect_uri
this.scope = scope.join(' ')
this.state = state
this.code = code
this.refresh_token = undefined
this.force_verify = force_verify
this.granted_scopes = undefined
this.user = undefined
}
redirect() {
const parsedOptions = toQueryParams({
client_id: this.client_id,
force_verify: this.force_verify,
redirect_uri: this.redirect_uri,
response_type: 'code',
scope: this.scope,
state: this.state,
})
return `https://id.twitch.tv/oauth2/authorize?${parsedOptions}`
}
private async getTokenFromCode() {
const parsedOptions = toQueryParams({
client_id: this.client_id,
client_secret: this.client_secret,
code: this.code,
grant_type: 'authorization_code',
redirect_uri: this.redirect_uri,
})
const url = 'https://id.twitch.tv/oauth2/token'
const response = await fetch(url, {
feat(oauth-providers): Add Twitch OAuth Provider (#981) * feat(twitch): Add type definitions for Twitch OAuth scopes * feat(twitch): Add additional type definitions for Twitch moderator scopes * feat(twitch): Add IRC and PubSub-specific chat scopes to types * feat(twitch): Add new type definitions for Twitch API responses * feat(twitch): Add new user-related scopes for Twitch API * feat(twitch): Add type definitions and import paths for Twitch provider * feat(twitch): Implement Twitch OAuth handlers and response types for mock api * feat(twitch): Add revokeToken function to handle OAuth token revocation * feat(twitch): Add Twitch OAuth middleware mocks and tests * feat(twitch): Implement Twitch OAuth authentication flow and user data retrieval * feat(twitch): Add custom state handling for Twitch OAuth middleware * docs(twitch): Update README with Twitch OAuth integration details * docs: Update Twitch API reference link for scopes in README * fix(twitch): Remove error handling for error_description in auth flow * refactor(twitch): Update token handling and response types for refresh and revoke * feat(twitch): Add token validation function for Twitch OAuth * feat(twitch): Add token validation handler and update response types * docs: Add token validation section to README for Twitch integration * chore(oauth-providers): changesets summary * fix(twitch): make redirect_uri optional in twitchAuth options * refactor(twitch): clean up commented code and improve test assertions * refactor(twitch): improve type assertions for JSON responses * refactor(twitch): update type assertion for JSON response handling * semver amendment Changed version from patch to minor * docs: update README with token validation instructions for Twitch --------- Co-authored-by: Younis-Ahmed <23105954+jonaahmed@users.noreply.github.com>
2025-03-12 16:55:47 +08:00
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: parsedOptions,
}).then((res) => res.json() as Promise<TwitchTokenResponse>)
feat(oauth-providers): Add Twitch OAuth Provider (#981) * feat(twitch): Add type definitions for Twitch OAuth scopes * feat(twitch): Add additional type definitions for Twitch moderator scopes * feat(twitch): Add IRC and PubSub-specific chat scopes to types * feat(twitch): Add new type definitions for Twitch API responses * feat(twitch): Add new user-related scopes for Twitch API * feat(twitch): Add type definitions and import paths for Twitch provider * feat(twitch): Implement Twitch OAuth handlers and response types for mock api * feat(twitch): Add revokeToken function to handle OAuth token revocation * feat(twitch): Add Twitch OAuth middleware mocks and tests * feat(twitch): Implement Twitch OAuth authentication flow and user data retrieval * feat(twitch): Add custom state handling for Twitch OAuth middleware * docs(twitch): Update README with Twitch OAuth integration details * docs: Update Twitch API reference link for scopes in README * fix(twitch): Remove error handling for error_description in auth flow * refactor(twitch): Update token handling and response types for refresh and revoke * feat(twitch): Add token validation function for Twitch OAuth * feat(twitch): Add token validation handler and update response types * docs: Add token validation section to README for Twitch integration * chore(oauth-providers): changesets summary * fix(twitch): make redirect_uri optional in twitchAuth options * refactor(twitch): clean up commented code and improve test assertions * refactor(twitch): improve type assertions for JSON responses * refactor(twitch): update type assertion for JSON response handling * semver amendment Changed version from patch to minor * docs: update README with token validation instructions for Twitch --------- Co-authored-by: Younis-Ahmed <23105954+jonaahmed@users.noreply.github.com>
2025-03-12 16:55:47 +08:00
if ('error' in response) {
throw new HTTPException(400, { message: response.error })
}
if ('access_token' in response) {
this.token = {
token: response.access_token,
expires_in: response.expires_in,
}
}
if ('refresh_token' in response) {
this.refresh_token = {
token: response.refresh_token,
expires_in: 0,
}
}
if ('scope' in response) {
this.granted_scopes = response.scope
}
}
async getUserData() {
await this.getTokenFromCode()
const response = (await fetch('https://api.twitch.tv/helix/users', {
headers: {
authorization: `Bearer ${this.token?.token}`,
'Client-ID': this.client_id,
},
}).then((res) => res.json())) as TwitchUserResponse | TwitchErrorResponse
if ('error' in response) {
throw new HTTPException(400, { message: JSON.stringify(response) })
}
if ('message' in response) {
throw new HTTPException(400, { message: JSON.stringify(response) })
}
if ('data' in response) {
this.user = response.data[0]
}
}
}