Overview
isAuthenticatedSE
and authenticateSE
enable you to implement bespoke authentication mechanisms not covered by default providers. These service extensions can be used for Proxy, SAML, and OIDC apps, and they must be used together.
isAuthenticatedSE
can be used to override the default behavior that determines if a user is already authenticated. authenticateSE
is then used to take control of how the authentication will be done.
Implementation
To create isAuthenticatedSE
and authenticateSE
go to Service Extensions.
From the right sidebar, click the + icon next to Authentication.
Enter a name and description for the service extension, and click Create.
The service extension code appears on the next page. From here, you can add assets, providers, claims, and/or metadata. When you've finished adding this information, click Update.
You will receive a confirmation message in the lower right corner that the service extension file has been updated.
You can now use this service extension in an existing or new user flow. For SAML and OIDC app user flows, the service extension can be selected as an Authentication Provider:

Click to enlarge
For Proxy app user flows, the service extension will appear as an Authentication Provider that can be selected when configuring your access control policies for a specific resource location.
Code Example
/etc/maverics/extensions/auth.go
package main
import (
"net/http"
"errors"
"crypto/sha256"
"encoding/hex"
"fmt"
"strings"
"github.com/strata-io/service-extension/orchestrator"
)
// IsAuthenticated checks if the current session is marked as authenticated by Okta.
func IsAuthenticated(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) bool {
logger := api.Logger()
logger.Debug("se", "determining if user is authenticated")
// Retrieve the current session
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
// Check if the session has the Okta authentication flag
isOktaAuth, err := session.GetString("okta.authenticated")
if err != nil {
logger.Error("se", "unable to retrieve session value", "error", err.Error())
return false
}
// Return true if authenticated
if isOktaAuth == "true" {
return true
}
return false
}
// Authenticate triggers the login flow using Okta as the Identity Provider.
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
logger := api.Logger()
logger.Debug("se", "authenticating user")
// Get the Okta identity provider
oktaIDP, err := api.IdentityProvider("okta")
if err != nil {
logger.Error("se", "failed to retrieve Okta IDP", "error", err.Error())
// Return a 500 error to the client if IDP is missing
http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
// Initiate the login flow through Okta
oktaIDP.Login(rw, req)
}
// LoadAttributes fetches additional user info from LDAP and stores it in the session.
func LoadAttributes(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) error {
logger := api.Logger()
logger.Debug("se", "loading custom attributes from LDAP")
// Retrieve the current session
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return err
}
// Get the user's email, required to query LDAP
mail, err := session.GetString("okta.email")
if err != nil {
return fmt.Errorf("failed to find user email required for LDAP query: %w", err)
}
// Get the LDAP attribute provider
ldap, err := api.AttributeProvider("ldap")
if err != nil {
return fmt.Errorf("failed to find LDAP attribute provider")
}
// Query LDAP for specific attributes
attrs, err := ldap.Query(mail, []string{"givenname", "sn", "mobile"})
if err != nil {
return fmt.Errorf("failed to query LDAP: %w", err)
}
// Store retrieved attributes in the session
for k, v := range attrs {
logger.Debug("se", "setting LDAP attribute on session", "attribute", k, "value", v)
_ = session.SetString(k, v)
}
// Save session to persist changes
err = session.Save()
if err != nil {
return fmt.Errorf("unable to save session state: %w", err)
}
return nil
}
// BackchannelAuthenticate performs direct credential verification using stored secrets.
func BackchannelAuthenticate(api orchestrator.Orchestrator, req *http.Request) error {
logger := api.Logger()
logger.Debug("se", "authenticating user in backchannel flow")
// Get credentials from form fields
username := req.Form.Get("username")
password := req.Form.Get("password")
// Get the secret provider to retrieve stored credentials
secrets, err := api.SecretProvider()
if err != nil {
logger.Error("se", "failed to retrieve secret provider", "error", err.Error())
return errors.New("failed to retrieve secret provider")
}
// Get stored password hash by username
pwdHash := secrets.GetString(username)
if len(pwdHash) == 0 {
return errors.New("invalid user credentials")
}
// Hash the input password
hash := sha256.Sum256([]byte(password))
hashHex := hex.EncodeToString(hash[:])
// Compare input hash with stored hash
if pwdHash != hashHex {
return errors.New("invalid user credentials")
}
return nil
}
// IsAuthorized checks whether the current user is part of the 'executives' group.
func IsAuthorized(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) bool {
logger := api.Logger()
logger.Debug("se", "determining if user is authorized")
// Retrieve session
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
// Get groups string and split into a slice
rawGroups, _ := session.GetString("okta.groups")
groups := strings.Split(rawGroups, ",")
// Check for membership in "executives"
for _, group := range groups {
if group == "executives" {
return true
}
}
return false
}
// BuildAccessTokenClaims creates a claim map with roles for inclusion in an access token.
func BuildAccessTokenClaims(api orchestrator.Orchestrator, _ *http.Request) (map[string]any, error) {
logger := api.Logger()
logger.Debug("se", "building access token claims")
// Get session
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return nil, err
}
// Retrieve user roles and include them in the claim map
roles, err := session.GetString("okta.roles")
return map[string]any{
"scope": roles,
}, err
}
// BuildIDTokenClaims creates a claim map with groups for inclusion in an ID token.
func BuildIDTokenClaims(api orchestrator.Orchestrator, _ *http.Request) (map[string]any, error) {
logger := api.Logger()
logger.Debug("se", "building ID token claims")
// Get session
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return nil, err
}
// Retrieve user groups and include them in the claim map
groups, err := session.GetString("okta.groups")
return map[string]any{
"groups": groups,
}, err
}