Request tokens
This commit is contained in:
parent
c61a32369c
commit
d3d9e87ce0
|
@ -1,8 +1,13 @@
|
||||||
import { redirect } from "@sveltejs/kit"
|
import { error, redirect, type Cookies } from "@sveltejs/kit"
|
||||||
import configuration from "./configuration"
|
import configuration from "./configuration"
|
||||||
|
|
||||||
const states = new Map<string, ReturnType<typeof setTimeout>>()
|
// Map of OAuth2 states
|
||||||
|
const states = new Map<string, { redirect_uri: string, timeout: ReturnType<typeof setTimeout> }>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Launch an OAuth2 login request for this request.
|
||||||
|
* @param req Request to launch the login for; required to obtain the Host header.
|
||||||
|
*/
|
||||||
export function launchLogin(req: Request) {
|
export function launchLogin(req: Request) {
|
||||||
// Create a state to be used in the OAuth2 authorization request
|
// Create a state to be used in the OAuth2 authorization request
|
||||||
const state = crypto.randomUUID()
|
const state = crypto.randomUUID()
|
||||||
|
@ -11,7 +16,7 @@ export function launchLogin(req: Request) {
|
||||||
const searchParams = new URLSearchParams({
|
const searchParams = new URLSearchParams({
|
||||||
response_type: "code",
|
response_type: "code",
|
||||||
client_id: configuration.oauth2.client.id,
|
client_id: configuration.oauth2.client.id,
|
||||||
redirect_uri: new URL(`/set`, req.url).toString(),
|
redirect_uri: req.url,
|
||||||
scope: "openid profile email",
|
scope: "openid profile email",
|
||||||
state
|
state
|
||||||
})
|
})
|
||||||
|
@ -20,9 +25,61 @@ export function launchLogin(req: Request) {
|
||||||
`?${searchParams.toString()}`,
|
`?${searchParams.toString()}`,
|
||||||
configuration.oauth2.endpoints.authenticate
|
configuration.oauth2.endpoints.authenticate
|
||||||
)
|
)
|
||||||
|
|
||||||
states
|
|
||||||
.set(state, setTimeout(() => states.delete(state), 60000))
|
|
||||||
|
|
||||||
return redirect(302, target.toString())
|
// cache state
|
||||||
|
// NO IDEA IF THIS WORKS IN SERVERLESS LOL
|
||||||
|
// not like this is going to be running serverless anyway
|
||||||
|
states
|
||||||
|
.set(
|
||||||
|
state,
|
||||||
|
{
|
||||||
|
timeout: setTimeout(
|
||||||
|
() => states.delete(state),
|
||||||
|
2*60*1000
|
||||||
|
),
|
||||||
|
redirect_uri: req.url
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
throw redirect(302, target.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request a token from the OAuth server
|
||||||
|
* @param params
|
||||||
|
* @returns Access token, its time-to-expiration, and refresh token if applicable
|
||||||
|
*/
|
||||||
|
export async function retrieveToken(
|
||||||
|
params:
|
||||||
|
{grant_type: "authorization_code", redirect_uri: string, code: string}
|
||||||
|
| {grant_type: "refresh_token", refresh_token: string}
|
||||||
|
) {
|
||||||
|
// Generate a query string for the request
|
||||||
|
const searchParams = new URLSearchParams({
|
||||||
|
...params,
|
||||||
|
client_id: configuration.oauth2.client.id,
|
||||||
|
client_secret: configuration.oauth2.client.secret
|
||||||
|
})
|
||||||
|
const url = new URL(
|
||||||
|
`?${searchParams.toString()}`,
|
||||||
|
configuration.oauth2.endpoints.token
|
||||||
|
)
|
||||||
|
|
||||||
|
let res = await fetch(url)
|
||||||
|
if (!res.ok)
|
||||||
|
throw error(401, "Couldn't retrieve token for user")
|
||||||
|
else
|
||||||
|
return (await res.json()) as { access_token: string, expires_in: number, refresh_token?: string }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRequestUser(request: Request, cookies: Cookies) {
|
||||||
|
const params = new URLSearchParams(request.url.split("?").slice(1).join("?"))
|
||||||
|
let token = cookies.get("token")
|
||||||
|
if (!token && params.has("code") && params.has("state")) {
|
||||||
|
if (!states.has(params.get("state")!))
|
||||||
|
throw error(401, "bad state")
|
||||||
|
|
||||||
|
token = params.get("code")!
|
||||||
|
cookies.set("token", token, { path: "/" })
|
||||||
|
}
|
||||||
}
|
}
|
4
src/lib/types.ts
Normal file
4
src/lib/types.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export interface User {
|
||||||
|
name: string
|
||||||
|
sub: string
|
||||||
|
}
|
|
@ -3,5 +3,5 @@ export async function load({ request, parent }) {
|
||||||
//const { user } = await parent();
|
//const { user } = await parent();
|
||||||
let user = null
|
let user = null
|
||||||
if (!user)
|
if (!user)
|
||||||
throw launchLogin(request)
|
launchLogin(request)
|
||||||
}
|
}
|
Loading…
Reference in a new issue