Skip to content

Commit

Permalink
fix: add state and code verification, more logs to debug issues
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickHeneise committed Sep 29, 2022
1 parent df5e744 commit 13d9d99
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 11 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ AUTH0_CLIENT_SECRET=
VITE_AUTH0_REDIRECT_URI=http://localhost:8080/api/auth/callback
VITE_AUTH0_MULTI_TENANT_MODE=false
VITE_SESSION_SECRET=hello-world-123
VITE_AUTH0_OFFLINE_ACCESS=false
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ Set `VITE_AUTH0_MULTI_TENANT_MODE=true` in `.env`

## Usage

### Environment Variables

See [.env.example](./env.example)

- `VITE_AUTH0_MULTI_TENANT_MODE` requires the Auth0 Organization setup
- `VITE_AUTH0_OFFLINE_ACCESS` requires the Auth0 API to be configured with
offline access

### vite.config.ts/js

There's an issue with vite throwing `process` is undefined errors when the
Expand Down
72 changes: 61 additions & 11 deletions src/api/callback.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { storage } from '../session.js'
import { parseCookie } from 'solid-start/session'

async function auth0UserInfo(accessToken) {
const endpoint = new URL(`https://${process.env.VITE_AUTH0_DOMAIN}/userinfo`)
Expand All @@ -17,18 +18,38 @@ async function auth0UserInfo(accessToken) {
return userInfo.json()
}

async function auth0FetchOAuthToken(code, redirectUrl) {
async function auth0FetchOAuthToken(code, state, redirectUrl, organization) {
const endpoint = new URL(
`https://${process.env.VITE_AUTH0_DOMAIN}/oauth/token`
)

const formData = new URLSearchParams()
const scopes = ['openid', 'profile', 'email']
formData.append('grant_type', 'authorization_code')
formData.append('client_id', process.env.VITE_AUTH0_CLIENT_ID)
formData.append('client_secret', process.env.AUTH0_CLIENT_SECRET)
formData.append('code', code)
formData.append('state', state)
formData.append('redirect_uri', redirectUrl)

if (process.env.VITE_AUTH0_OFFLINE_ACCESS === 'true') {
scopes.push('offline_access')
}
formData.append('scope', scopes.join(' '))

if (organization) {
formData.append('organization', organization)
}

if (process.env.VITE_AUTH0_AUDIENCE) {
formData.append('audience', process.env.VITE_AUTH0_AUDIENCE)
}

if (process.env.DEBUG) {
console.log('formData')
console.log(formData)
}

const authToken = await fetch(endpoint, {
method: 'POST',
body: formData
Expand All @@ -39,21 +60,48 @@ async function auth0FetchOAuthToken(code, redirectUrl) {

export default async function get(request) {
let baseUrl = process.env.VITE_BASE_URL
if (process.env.DEBUG) {
console.log('baseUrl', baseUrl)
}

const url = new URL(request.url)
const session = await storage.getSession()
const headers = new Headers()
const url = new URL(request.url)
const params = url.searchParams
const code = url.searchParams.get('code')
const state = url.searchParams.get('state')
const cookies = parseCookie(request.headers.get('Cookie'))
const verification = JSON.parse(cookies[`com.auth0.auth.${state}`])

if (!verification) {
console.error('No verification cookie found')
return new Response(JSON.stringify({ error: 'verification failed' }), {
status: 500
})
}

// TODO: security: check response state & cookie state
// const requestHeaders = new Headers(request.headers)
// const requestCookies = requestHeaders.get('cookie')
if (process.env.DEBUG) {
console.log('state verification')
console.log(state)
console.log(verification)
}

if (params.get('code') === undefined || params.get('code') === null) {
if (code === undefined || code === null) {
console.error('No code found')
return new Response(JSON.stringify({ error: 'missing code' }), {
status: 500
})
}

if (state !== verification.state) {
console.error('Code and state do not match verification')
return new Response(
JSON.stringify({ error: 'code and state verification failed' }),
{
status: 403
}
)
}

let redirectUrl = process.env.VITE_AUTH0_REDIRECT_URI
if (process.env.VITE_AUTH0_MULTI_TENANT_MODE === 'true') {
const orgName = url.hostname.split('.')[0]
Expand All @@ -65,17 +113,19 @@ export default async function get(request) {
}

const jsonAuthToken = await auth0FetchOAuthToken(
params.get('code'),
redirectUrl
code,
state,
redirectUrl,
verification.organization
)

if (process.env.DEBUG === 'true') {
if (process.env.DEBUG) {
console.log('auth0FetchOAuthToken')
console.log(jsonAuthToken)
}

const userInfo = await auth0UserInfo(jsonAuthToken.access_token)
if (process.env.DEBUG === 'true') {
if (process.env.DEBUG) {
console.log('auth0UserInfo')
console.log(userInfo)
}
Expand Down

0 comments on commit 13d9d99

Please sign in to comment.