Last active
July 6, 2020 19:07
-
-
Save stctheproducer/f312c1f4a3c7e7a0c8953eb9563bee62 to your computer and use it in GitHub Desktop.
I am getting an error in which my auth session is saved in redis but doesn't seem to be propagated to rest of the application. I am using FusionAuth as my authentication server. Below are my files including their configurations.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
authenticator: 'session', | |
/* | |
|-------------------------------------------------------------------------- | |
| Session | |
|-------------------------------------------------------------------------- | |
| | |
| Session authenticator makes use of sessions to authenticate a user. | |
| Session authentication is always persistent. | |
| | |
*/ | |
session: { | |
serializer: 'lucid', | |
model: 'App/Models/User', | |
scheme: 'session', | |
uid: 'email', | |
password: 'password', | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async authorize({ request, response }) { | |
const { response_type } = request.get() | |
try { | |
// Check if OAuth flow is Authorization Code Grant Request | |
if (response_type !== Env.get('OAUTH2_FLOW_TYPE')) { | |
response.badRequest() | |
} | |
// Redirect to FusionAuth | |
response.redirect( | |
`${Env.get('FUSIONAUTH_URL')}/oauth2/authorize`, | |
true, | |
307 | |
) | |
} catch ({ message, stack }) { | |
Logger.error('%j', { message, stack }) | |
} | |
} | |
// Handle token exchange | |
async token({ request, response }) { | |
const { code, redirect_uri, client_id } = request.post() | |
// Check for code in request | |
if (!code) { | |
throw new Error('An authorization code was not received') | |
} | |
// Exchange authorization code for an access token | |
const { data } = await axios({ | |
url: `${Env.get('FUSIONAUTH_URL')}/oauth2/token`, | |
method: 'POST', | |
data: stringify({ | |
client_id, | |
client_secret: Env.get('FUSIONAUTH_CLIENT_SECRET'), | |
code, | |
grant_type: 'authorization_code', | |
redirect_uri, | |
}), | |
headers, | |
}) | |
// Logger.info('Login data: %j', data) | |
response.send(data) | |
} | |
// Handle user information | |
async info({ request, response, auth, session }) { | |
const token = request.header('authorization') | |
// Logger.info('Current Token: %s', token) | |
try { | |
// Check for token | |
if (token) { | |
// Introspect token | |
const { data: introspectResponse } = await axios({ | |
url: `${Env.get('FUSIONAUTH_URL')}/oauth2/introspect`, | |
method: 'post', | |
data: stringify({ | |
client_id: Env.get('FUSIONAUTH_CLIENT_ID'), | |
token: token.substr(7), | |
}), | |
headers, | |
}) | |
// Check if token is still active | |
if (introspectResponse.active) { | |
const { data: registration } = await axios({ | |
url: `${Env.get('FUSIONAUTH_URL')}/api/user/registration/${ | |
introspectResponse.sub | |
}/${Env.get('FUSIONAUTH_CLIENT_ID')}`, | |
method: 'get', | |
headers: { | |
Authorization: Env.get('FUSIONAUTH_API_KEY'), | |
}, | |
}) | |
const { data } = await axios({ | |
url: `${Env.get('FUSIONAUTH_URL')}/oauth2/userinfo`, | |
method: 'get', | |
headers: { | |
Authorization: token, | |
}, | |
}) | |
// Logger.info('UserInfo: %j', data) | |
const userData = Object.assign(introspectResponse, data, registration) | |
// Standardize phone numbers | |
let phoneNo = undefined | |
if (userData.phone_number) { | |
// If the phone number isn't prefixed | |
if (!userData.phone_number.startsWith('+')) { | |
// if the phone number starts with '0' | |
if (userData.phone_number.startsWith('0')) { | |
phoneNo = '+26' + userData.phone_number | |
} else { | |
phoneNo = '+' + userData.phone_number | |
} | |
} else { | |
phoneNo = userData.phone_number | |
} | |
} | |
// User details to be saved | |
const userDetails = { | |
username: userData.preferred_username, | |
first_name: userData.given_name, | |
middle_name: userData.middle_name ? userData.middle_name : null, | |
last_name: userData.family_name, | |
phone_number: phoneNo, | |
email: userData.email, | |
email_verified: userData.email_verified, | |
} | |
// search for existing user | |
const whereClause = { | |
email: userData.email, | |
} | |
const user = await User.findOrCreate(whereClause, userDetails) | |
// Logger.info('Found user: %j', user) | |
// Get user roles | |
const Role = use('Adonis/Acl/Role') | |
const roleAdmin = await Role.findBy('slug', 'admin') | |
const roleManager = await Role.findBy('slug', 'manager') | |
const roleUser = await Role.findBy('slug', 'user') | |
const roles = userData.roles | |
// Get roles to sync with user | |
const syncRoles = roles.map((role) => { | |
switch (role) { | |
case 'admin': | |
return roleAdmin.id | |
case 'manager': | |
return roleManager.id | |
default: | |
return roleUser.id | |
} | |
}) | |
// Attach roles to user and login | |
await user.roles().sync(syncRoles) | |
await auth.loginViaId(user.id) | |
// Logger.info('Logged in: %j', loggedIn) | |
Logger.info('Logged in user with ID: %i', user.id) | |
// Logger.info('userData: %j', userData) | |
response.send(userData) | |
} else { | |
response.unauthorized('Access token expired') | |
} | |
} else { | |
Logger.error('Unauthorized: No token detected') | |
response.unauthorized('Not logged in!') | |
} | |
// Logger.info('Session store: %j', await session.all()) | |
} catch ({ message, stack }) { | |
Logger.error('%j', { message, stack }) | |
} | |
} | |
// Handle logout for fusionauth | |
async logout({ auth, response, session }) { | |
await auth.logout() | |
response.redirect( | |
`${Env.get('FUSIONAUTH_URL')}/oauth2/logout?client_id=${Env.get( | |
'FUSIONAUTH_CLIENT_ID' | |
)}&tenant_id=${Env.get('FUSIONAUTH_TENANT_ID')}` | |
) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auth: { | |
// Options | |
plugins: ['~/plugins/auth.js'], | |
defaultStrategy: 'fusionauth', | |
cookie: { | |
prefix: 'auth.', | |
options: { | |
path: '/', | |
secure: false | |
} | |
}, | |
scopeKey: 'roles', | |
redirect: { | |
login: '/', | |
logout: '/', | |
callback: '/', | |
home: '/home' | |
}, | |
strategies: { | |
// FusionAuth via Adonis | |
fusionauth: { | |
_scheme: 'oauth2', | |
authorization_endpoint: `${process.env.API_URL}/user/authorize`, | |
userinfo_endpoint: `${process.env.API_URL}/user/info`, | |
scope: ['offline_access'], | |
access_type: 'offline', | |
access_token_endpoint: `${process.env.API_URL}/user/token`, | |
response_type: 'code', | |
token_type: 'Bearer', | |
client_id: `${process.env.FUSIONAUTH_CLIENT_ID}`, | |
token_key: 'access_token', | |
refresh_token_key: 'refresh_token', | |
state: crypto.randomBytes(16).toString('hex') | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Route.get('session-data', async ({ request, response, auth, session }) => { | |
try { | |
// let user = await auth.getUser() | |
const check = await auth.check() | |
Logger.info('Session: %j', session.all()) | |
response.json(check) | |
} catch ({ message }) { | |
Logger.error(message) | |
} | |
}) | |
// Response | |
// error: E_INVALID_SESSION: Invalid session |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
const Env = use('Env') | |
module.exports = { | |
/* | |
|-------------------------------------------------------------------------- | |
| Session Driver | |
|-------------------------------------------------------------------------- | |
| | |
| The session driver to be used for storing session values. It can be | |
| cookie, file or redis. | |
| | |
| For `redis` driver, make sure to install and register `@adonisjs/redis` | |
| | |
*/ | |
driver: Env.get('SESSION_DRIVER', 'cookie'), | |
/* | |
|-------------------------------------------------------------------------- | |
| Cookie Name | |
|-------------------------------------------------------------------------- | |
| | |
| The name of the cookie to be used for saving session id. Session ids | |
| are signed and encrypted. | |
| | |
*/ | |
cookieName: 'adonis-session', | |
/* | |
|-------------------------------------------------------------------------- | |
| Clear session when browser closes | |
|-------------------------------------------------------------------------- | |
| | |
| If this value is true, the session cookie will be temporary and will be | |
| removed when browser closes. | |
| | |
*/ | |
clearWithBrowser: true, | |
/* | |
|-------------------------------------------------------------------------- | |
| Session age | |
|-------------------------------------------------------------------------- | |
| | |
| This value is only used when `clearWithBrowser` is set to false. The | |
| age must be a valid https://npmjs.org/package/ms string or should | |
| be in milliseconds. | |
| | |
| Valid values are: | |
| '2h', '10d', '5y', '2.5 hrs' | |
| | |
*/ | |
age: '2h', | |
/* | |
|-------------------------------------------------------------------------- | |
| Cookie options | |
|-------------------------------------------------------------------------- | |
| | |
| Cookie options defines the options to be used for setting up session | |
| cookie | |
| | |
*/ | |
cookie: { | |
httpOnly: true, | |
sameSite: 'none', | |
path: '/', | |
}, | |
/* | |
|-------------------------------------------------------------------------- | |
| Sessions location | |
|-------------------------------------------------------------------------- | |
| | |
| If driver is set to file, we need to define the relative location from | |
| the temporary path or absolute url to any location. | |
| | |
*/ | |
file: { | |
location: 'sessions', | |
}, | |
/* | |
|-------------------------------------------------------------------------- | |
| Redis config | |
|-------------------------------------------------------------------------- | |
| | |
| The configuration for the redis driver. | |
| | |
*/ | |
redis: 'self::redis.local', | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment