-
Notifications
You must be signed in to change notification settings - Fork 99
/
seznam.ts
179 lines (153 loc) · 4.88 KB
/
seznam.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import defu from 'defu'
import type { H3Event } from 'h3'
import { eventHandler, getQuery, sendRedirect } from 'h3'
import { withQuery } from 'ufo'
import { getOAuthRedirectURL, handleAccessTokenErrorResponse, handleMissingConfiguration, requestAccessToken } from '../utils'
import { useRuntimeConfig } from '#imports'
import type { OAuthConfig } from '#auth-utils'
export interface OAuthSeznamConfig {
/**
* Seznam OAuth Client ID
* @default process.env.NUXT_OAUTH_SEZNAM_CLIENT_ID
*/
clientId?: string
/**
* Seznam OAuth Client Secret
* @default process.env.NUXT_OAUTH_SEZNAM_CLIENT_SECRET
*/
clientSecret?: string
/**
* Seznam OAuth Scope
* @default ['identity']
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
* @example ['identity', 'avatar']
*/
scope?: string[]
/**
* Redirect URL to to allow overriding for situations like prod failing to determine public hostname
* Redirect URL has to be set as well in the Seznam OAuth settings https://vyvojari.seznam.cz/oauth/admin in order for it to work
* @see https://vyvojari.seznam.cz/oauth/admin
* @default process.env.NUXT_OAUTH_SEZNAM_REDIRECT_URL
*/
redirectURL?: string
/**
* Seznam OAuth Authorization URL
* @default 'https://login.szn.cz/api/v1/oauth/auth'
*/
authorizationURL?: string
/**
* Seznam OAuth Token URL
* @default 'https://login.szn.cz/api/v1/oauth/token'
*/
tokenURL?: string
/**
* Seznam OAuth User URL
* @default 'https://login.szn.cz/api/v1/user'
*/
userURL?: string
}
export interface OAuthSeznamUser {
/**
* Unique persistent user account identifier
*/
oauth_user_id: string
/**
* The user's e-mail address or null for users without an e-mail
*/
email: string | null
/**
* Given name (when available)
*/
firstname: string
/**
* Family name (when available)
*/
lastname: string
/**
* User account identifier suitable for usage within the Seznam ad infrastructure
*/
advert_user_id: string
/**
* (only when provided and validated by the user; null otherwise)
* Available only when you use the contact-phone scope
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
*/
contact_phone?: string | null
/**
* the image's URL
* Available only when you use the avatar scope
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
*/
avatar_url?: string | null
/**
* true/false value corresponding to the user's adult status
* Available only when you use the avatar scope
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
*/
adulthood?: boolean
/**
* date of birth in the ISO 8601 format (only when present; null otherwise)
* Available only when you use the birthday scope
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
*/
birthday?: string | null
/**
* one of the allowed strings "Male" / "Female" / "Other" (null if not set)
* Available only when you use the gender scope
* @see https://vyvojari.seznam.cz/oauth/scopes?lang=en
*/
gender?: string | null
}
export function defineOAuthSeznamEventHandler({ config, onSuccess, onError }: OAuthConfig<OAuthSeznamConfig, OAuthSeznamUser>) {
return eventHandler(async (event: H3Event) => {
config = defu(config, useRuntimeConfig(event).oauth?.seznam, {
authorizationURL: 'https://login.szn.cz/api/v1/oauth/auth',
tokenURL: 'https://login.szn.cz/api/v1/oauth/token',
userURL: 'https://login.szn.cz/api/v1/user',
}) as OAuthSeznamConfig
const query = getQuery<{ code?: string, state?: string }>(event)
if (!config.clientId || !config.clientSecret) {
return handleMissingConfiguration(event, 'seznam', ['clientId', 'clientSecret'], onError)
}
const redirectURL = config.redirectURL || getOAuthRedirectURL(event)
if (!query.code) {
config.scope = config.scope || ['identity'] // identity is mandatory
// Redirect to Seznam Oauth page
return sendRedirect(
event,
withQuery(config.authorizationURL as string, {
response_type: 'code',
client_id: config.clientId,
redirect_uri: redirectURL,
scope: config.scope.join(','),
state: query.state || '',
}),
)
}
const tokens = await requestAccessToken(config.tokenURL as string, {
body: {
grant_type: 'authorization_code',
code: query.code as string,
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: redirectURL,
},
})
if (tokens.error) {
return handleAccessTokenErrorResponse(event, 'seznam', tokens, onError)
}
const accessToken = tokens.access_token
const user: OAuthSeznamUser = await $fetch(
config.userURL as string,
{
headers: {
Authorization: `bearer ${accessToken}`,
},
},
)
return onSuccess(event, {
tokens,
user,
})
})
}