fix(#699): auth token

pull/308/head
Rakov 2 years ago committed by Gitea
parent 888ac35156
commit fc3a3c052c
  1. 41
      public/silent-refresh.html
  2. 28
      src/features/AuthStore/hooks/useAuth.tsx
  3. 1
      src/features/SystemSettings/hooks.tsx
  4. 2
      src/helpers/cookie/index.tsx
  5. 51
      src/requests/getCredentials.tsx

@ -1,15 +1,46 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<title></title> <title></title>
</head> </head>
<body> <body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.11.5/oidc-client.min.js" integrity="sha512-pGtU1n/6GJ8fu6bjYVGIOT9Dphaw5IWPwVlqkpvVgqBxFkvdNbytUh0H8AP15NYF777P4D3XEeA/uDWFCpSQ1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.11.5/oidc-client.min.js"
integrity="sha512-pGtU1n/6GJ8fu6bjYVGIOT9Dphaw5IWPwVlqkpvVgqBxFkvdNbytUh0H8AP15NYF777P4D3XEeA/uDWFCpSQ1g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script> <script>
new Oidc.UserManager().signinSilentCallback() new Oidc.UserManager().signinSilentCallback()
.catch((err) => { .then(() => {
console.error('OIDC: silent refresh callback error', err); const refreshToken = new URLSearchParams(document.location.search).get('refresh_token');
});
if (refreshToken && /iPad|iPhone|iPod/.test(navigator.userAgent)) {
const getDomain = () => {
if (! '%NODE_ENV%' || '%NODE_ENV%' === 'development') {
return 'localhost';
} else {
return '.insports.tv';
}
};
const parseJwt = (value) => {
const base64Url = value.split('.')[1];
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(window.atob(base64).split('').map((c) => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`).join(''));
return JSON.parse(jsonPayload);
};
const saveRefreshToken = (value) => {
const ref = parseJwt(value);
const expires = `expires=${new Date((ref.exp * 1000)).toUTCString()}`;
document.cookie = `refresh_token=${value};${expires};path=/;domain=${getDomain()};secure;SameSite=None`;
};
saveRefreshToken(refreshToken);
}
})
.catch((err) => {
console.error('OIDC: silent refresh callback error', err);
});
</script> </script>
</body> </body>
</html>
</html>

@ -14,7 +14,7 @@ import isString from 'lodash/isString'
import isBoolean from 'lodash/isBoolean' import isBoolean from 'lodash/isBoolean'
import includes from 'lodash/includes' import includes from 'lodash/includes'
import { PAGES } from 'config' import { PAGES, isIOS } from 'config'
import { import {
addLanguageUrlParam, addLanguageUrlParam,
@ -24,6 +24,7 @@ import {
setCookie, setCookie,
removeCookie, removeCookie,
isMatchPage, isMatchPage,
getDomain,
} from 'helpers' } from 'helpers'
import { import {
@ -65,6 +66,14 @@ export const useAuth = () => {
}) })
} }
const parseJwt = (value: string) => {
const base64Url = value.split('.')[1]
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
const jsonPayload = decodeURIComponent(window.atob(base64).split('').map((c) => `%${(`00${c.charCodeAt(0).toString(16)}`).slice(-2)}`).join(''))
return JSON.parse(jsonPayload)
}
const login = useCallback(async () => { const login = useCallback(async () => {
userManager.signinRedirect({ extraQueryParams: { lang } }) userManager.signinRedirect({ extraQueryParams: { lang } })
}, [lang]) }, [lang])
@ -79,6 +88,7 @@ export const useAuth = () => {
removeToken() removeToken()
if (key !== 'saveToken') { if (key !== 'saveToken') {
removeCookie('access_token') removeCookie('access_token')
removeCookie('refresh_token')
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [lang]) }, [lang])
@ -158,12 +168,21 @@ export const useAuth = () => {
} }
} }
const signinRedirectCallback = useCallback(() => { const saveRefreshToken = (value: string) => {
const ref = parseJwt(value)
const expires = `expires=${new Date((ref.exp * 1000)).toUTCString()}`
document.cookie = `refresh_token=${value};${expires};path=/;domain=${getDomain()};secure;SameSite=None`
}
const signinRedirectCallback = useCallback(async (refreshToken: string | null) => {
setPage(history.location.pathname) setPage(history.location.pathname)
userManager.signinRedirectCallback() userManager.signinRedirectCallback()
.then((loadedUser) => { .then((loadedUser) => {
storeUser(loadedUser) storeUser(loadedUser)
if (isIOS && refreshToken) saveRefreshToken(refreshToken)
queryParamStorage.clear() queryParamStorage.clear()
if (page.includes(PAGES.useraccount)) { if (page.includes(PAGES.useraccount)) {
history.push(PAGES.home) history.push(PAGES.home)
@ -187,10 +206,13 @@ export const useAuth = () => {
const searchToken = urlSearch.get('access_token') const searchToken = urlSearch.get('access_token')
const searchRefToken = urlSearch.get('id_token') const searchRefToken = urlSearch.get('id_token')
const searchExp = urlSearch.get('expires_in') const searchExp = urlSearch.get('expires_in')
const refreshToken = urlSearch.get('refresh_token')
const isRedirectedBackFromAuthProvider = Boolean(searchToken && searchRefToken && searchExp) const isRedirectedBackFromAuthProvider = Boolean(searchToken && searchRefToken && searchExp)
isRedirectedBackFromAuthProvider ? signinRedirectCallback() : checkUser() isRedirectedBackFromAuthProvider
? signinRedirectCallback(refreshToken)
: checkUser()
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
checkUser, checkUser,

@ -38,6 +38,7 @@ export const useSystemSettings = () => {
setSelectedApi(api.value) setSelectedApi(api.value)
removeToken() removeToken()
removeCookie('access_token') removeCookie('access_token')
removeCookie('refresh_token')
window.location.reload() window.location.reload()
} }

@ -29,7 +29,7 @@ export const checkCookie = (name: string) => {
return token[0] return token[0]
} }
const getDomain = () => ( export const getDomain = () => (
process.env.NODE_ENV === 'development' process.env.NODE_ENV === 'development'
? 'localhost' ? 'localhost'
: '.insports.tv' : '.insports.tv'

@ -0,0 +1,51 @@
import { AUTH_SERVICE } from 'config'
import { ClientIds } from 'config/clients/types'
export type TokenFailedResponse = {
error?: {
code: number,
message: string,
},
ok: false,
}
type TokenResponse = {
access_token: string,
id_token: string,
refresh_token: string,
}
type TokenProps = {
client_id: ClientIds,
email?: 'string',
grant_type?: 'password' | 'refresh_token',
id_token?: 'string',
password?: 'string',
refresh_token: string,
}
export const getCredentials = async ({
client_id,
grant_type = 'refresh_token',
refresh_token,
}: TokenProps): Promise<TokenResponse> => {
const url = new URL(`${AUTH_SERVICE}/token`)
const credetials = await fetch(url, {
body: JSON.stringify({
client_id,
grant_type,
refresh_token,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
})
const body: TokenResponse | TokenFailedResponse = await credetials.json()
if ('ok' in body) return Promise.reject(body.error)
return Promise.resolve(body)
}
Loading…
Cancel
Save