@cambridge-pte/adonisjs6-ally-okta
v2.0.0
Published
Custom adonisjs6/ally provider for Okta.
Readme
AdonisJS 6 Ally Okta Provider
A custom OAuth2 provider for AdonisJS Ally that adds Okta authentication support.
Getting Started
Installation
Install the package using your preferred package manager:
npm install @cambridge-pte/adonisjs6-ally-oktayarn add @cambridge-pte/adonisjs6-ally-oktapnpm add @cambridge-pte/adonisjs6-ally-oktaConfiguration
Configure the package by running:
node ace configure @cambridge-pte/adonisjs6-ally-oktaEnvironment Variables
Add the required environment variables to your .env file:
OKTA_DRIVER_CLIENT_ID=your_okta_client_id
OKTA_DRIVER_CLIENT_SECRET=your_okta_client_secret
OKTA_DRIVER_AUTHORIZE_URL=https://your-domain.okta.com/oauth2/default/v1/authorize
OKTA_DRIVER_USER_INFO_URL=https://your-domain.okta.com/oauth2/default/v1/userinfo
OKTA_DRIVER_TOKEN_URL=https://your-domain.okta.com/oauth2/default/v1/token
OKTA_DRIVER_RESPONSE_TYPE=code
OKTA_DRIVER_SCOPES=openid email profileAlly Configuration
Update your config/ally.ts file to include the Okta provider:
import { defineConfig } from '@adonisjs/ally'
import { OktaDriverService } from '@cambridge-pte/adonisjs6-ally-okta'
import env from '#start/env'
const allyConfig = defineConfig({
// ... other providers like github, google, etc
okta: OktaDriverService({
clientId: env.get('OKTA_DRIVER_CLIENT_ID'),
clientSecret: env.get('OKTA_DRIVER_CLIENT_SECRET'),
callbackUrl: `${env.get('APP_URL')}/auth/okta/callback`,
authorizeUrl: env.get('OKTA_DRIVER_AUTHORIZE_URL'),
accessTokenUrl: env.get('OKTA_DRIVER_TOKEN_URL'),
userInfoUrl: env.get('OKTA_DRIVER_USER_INFO_URL'),
scopes: env.get('OKTA_DRIVER_SCOPES'),
responseType: env.get('OKTA_DRIVER_RESPONSE_TYPE'),
}),
})
export default allyConfig
// TypeScript module augmentation for proper type inference
declare module '@adonisjs/ally/types' {
interface SocialProviders extends InferSocialProviders<typeof allyConfig> {}
}Usage
Basic Authentication Flow
Create routes for handling the OAuth flow:
// start/routes.ts
import router from '@adonisjs/core/services/router'
router.get('/okta/callback', '#controllers/oidc_controller.callback')In your controller:
import type { HttpContext } from '@adonisjs/core/http'
import User from '#models/user'
// modify as needed
const API_TOKEN_EXPIRY = '1d'
export default class OIDCController {
async callback({ ally, auth, response }: HttpContext) {
const okta = ally.use('okta')
if (okta.accessDenied()) {
return response.badRequest({ error: 'Access was denied' })
}
if (okta.stateMisMatch()) {
return response.badRequest({ error: 'Request expired. Retry again' })
}
if (okta.hasError()) {
return response.badRequest({ error: okta.getError() })
}
try {
const { token: accessToken } = await okta.accessToken()
const { name: userName, email } = await okta.userFromToken(accessToken)
const user = await User.updateOrCreate(
{
email,
},
{
fullName: userName,
email,
}
)
const token = await auth.use('user').login(user, {
expiresIn: API_TOKEN_EXPIRY,
})
return response.json({
success: true,
message: 'Authentication successful',
data: {
token,
userName,
email,
},
})
} catch (error) {
return response.status(500).json({
success: false,
error: error.message,
})
}
}
}Note: This example assumes you're handling the initial OAuth redirect from your frontend application or another service. The callback route processes the authorization code returned by Okta after user authentication.
Available Scopes
The provider supports the following Okta scopes:
openid- Required for OpenID Connectemail- Access to email addressprofile- Access to profile informationaddress- Access to address informationphone- Access to phone numberoffline_access- Refresh token supportgroups- Access to group membership
User Object
The returned user object contains:
{
id: string // Okta user ID (sub claim)
name: string // Full name
nickName: string // Display name
email: string // Email address (from preferred_username)
avatarUrl: string // Profile picture URL
emailVerificationState: 'verified' | 'unverified'
original: object // Raw response from Okta
}TypeScript Support
This package includes full TypeScript support with proper type definitions for:
- Configuration options
- User object structure
- Available scopes
- Driver methods
Setting up TypeScript Support
The module augmentation should be added to your config/ally.ts file as shown above:
// In your config/ally.ts file
declare module '@adonisjs/ally/types' {
interface SocialProviders extends InferSocialProviders<typeof allyConfig> {}
}This enables full TypeScript intellisense for the Okta driver, allowing you to use:
// In your controllers
const okta = ally.use('okta') // Properly typed as OktaDriver
await okta.user() // Full method autocomplete and type safetyImporting Types
Import types when needed for configuration or custom implementations:
import type { OktaDriverConfig, OktaDriverScopes } from '@cambridge-pte/adonisjs6-ally-okta/types'License
MIT License - see the LICENSE.md file for details.
