OIDC applications
The Maverics Identity Orchestrator can be used as an IDP to protect OIDC apps.
oidcProvider
must be defined.Configuration options
Name
name
is a unique identifier for the app.
Type
type
represents the application type. When defining OIDC apps, the type
should be oidc
.
Client ID
clientID
is a unique ID used by client applications to identify themselves.
Client Secret
clientSecret
is a secret used for authenticating client applications. The value of
the secret can be stored in a secret provider.
Authentication Redirect URLs
redirectURLs
are a list of the allowed URLs the response of an authentication
request can be sent.
Logout Redirect URLs
logoutRedirectURLs
are a list of the allowed URLs the response of a logout request
can be sent.
Claims Mapping
claimsMapping
provides a way to map attributes on a user’s session to
standard claims on the ID token. The claims added to the ID token are determined by
the value of the scope query parameter sent in the authorization request. The scopes
supported, in addition to the required openid
scope are email
, profile
,
address
and phone
. The mapping of claim values to a scope is listed in
OpenID Connect Core 1.0, section 5.4.
Returning a nonce provided in the authorization request via a claim in the ID token response is supported as well.
For example, if email
and profile
scopes are requested in the authorization
request, the IDP being used is azure
, and the claims mapping contains mappings to
Azure attributes, then the email
and profile
claims will be included in the ID
token response with the value of the associated attribute.
Attribute Providers
attrProviders
are an optional configuration for an identity system or data store from which the OIDCProvider may retrieve additional attributes used in claimsMapping
.
Connector
connector
is a reference to the name of the defined connector which will be used as an attribute provider.
Username Mapping
usernameMapping
defines the attribute that will be used as a search key to query for the user’s attributes.
Authentication
authentication
defines how users are authenticated for this app.
IDPs
idps
lists the IDPs which will be used to authenticate the user.
IsAuthenticated service extension
isAuthenticatedSE
is an optional service extension that can be used to override the
default behavior that determines if a user is already authenticated. This extension
must be used with authenticateSE
.
Authenticate service extension
authenticateSE
is an optional service extension used to take control of how
authentication will be done. This extension must be used with isAuthenticatedSE
.
Access Token
accessToken
defines the configuration for the OAuth access token.
Type
type
can be set to either jwt
(default) or opaque
.
Length
length
defines the length of an opaque
access token. The length can set to between
22 and 256 characters. If unset, the default length
is 28 characters.
Lifetime Seconds
lifetimeSeconds
controls the lifetime of an access token. By default, access tokens
have a lifetime of one hour.
Refresh Token
refreshToken
defines the configuration for the OAuth refresh token. Refresh tokens
are used to get a new access token without user interaction.
Refresh tokens are automatically rotated with every access token refresh. That is, everytime a refresh token is used to generate a new access token, a new refresh token is also returned. If a previously issued refresh token is reused outside an acceptable window, the active refresh token will be invalidated.
Refresh tokens are rotated to protect against refresh token replay attacks and compromised long-lived refresh tokens. For more information, please reference the OAuth Security Topics RFC.
Allow Offline Access
allowOfflineAccess
defines whether a client can request refresh tokens.
Refresh tokens will only be issued if the allowOfflineAccess
flag is set to true
and the authorization request includes the offline_access
scope.
Length
length
can be set to between 22 and 256 characters to define the length of a
refresh token. If unset, the default length
is 28 characters.
AllowedAudiences
allowedAudiences
is an optional configuration that represents a list of audiences
that are allowed to consume access tokens. When a client makes a request to
the authorization endpoint, an optional resource
parameter can be included that
indicates the target audience of the token. The value provided in the resource
parameter must be on the list of allowed audiences.
This configuration is used when resource servers, such as APIs, authorize via the access token. For more information, please reference RFC 9068.
BuildIDTokenClaims service extension
The buildIDTokenClaimsSE
is an optional service extension that can customize how
claims in the ID token are built.
BuildAccessTokenClaims service extension
The buildAccessTokenClaimsSE
is an optional service extension that can customize
how claims in the access token are built.
Examples
Basic OIDC App Config Example
apps:
- name: exampleOIDCApp
type: oidc
clientID: exampleClientID
clientSecret: <exampleClientSecret>
redirectURLs:
- https://app.enterprise.com/oidc
logoutRedirectURLs:
- https://app.enterprise.com/oidc/logout
attrProviders:
- connector: ldap
usernameMapping: okta.email
authentication:
idps:
- okta
claimsMapping:
email: ldap.mail
given_name: ldap.givenname
family_name: ldap.sn
OIDC App With Service Extension
apps:
- name: exampleOIDCApp
type: oidc
clientID: exampleClientID
clientSecret: <exampleClientSecret>
redirectURLs:
- https://app.enterprise.com/oidc
authentication:
isAuthenticatedSE:
funcName: IsAuthenticated
file: /etc/maverics/extensions/auth.go
authenticateSE:
funcName: Authenticate
file: /etc/maverics/extensions/auth.go
buildAccessTokenClaimsSE:
funcName: BuildAccessTokenClaims
file: /etc/maverics/extensions/auth.go
buildIDTokenClaimsSE:
funcName: BuildIDTokenClaims
file: /etc/maverics/extensions/auth.go
claimsMapping:
email: okta.email
/etc/maverics/extensions/auth.go
package main
import (
"net/http"
"github.com/strata-io/service-extension/orchestrator"
)
func IsAuthenticated(api orchestrator.Orchestrator, _ http.ResponseWriter, _ *http.Request) bool {
logger := api.Logger()
logger.Debug("se", "determining if user is authenticated")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return false
}
isOktaAuth, err := session.GetString("okta.authenticated")
if err != nil {
logger.Error("se", "unable to retrieve session value", "error", err.Error())
return false
}
if isOktaAuth == "true" {
return true
}
return false
}
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) {
logger := api.Logger()
logger.Debug("se", "authenticating user")
oktaIDP, err := api.IdentityProvider("okta")
if err != nil {
logger.Error(
"se", "failed to retrieve Okta IDP",
"error", err.Error(),
)
http.Error(
rw,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError,
)
return
}
oktaIDP.Login(rw, req)
}
func BuildAccessTokenClaims(api orchestrator.Orchestrator, _ *http.Request) (map[string]any, error) {
logger := api.Logger()
logger.Debug("se", "building access token claims")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return nil, err
}
roles, err := session.GetString("okta.roles")
return map[string]any{
"scope": roles,
}, err
}
func BuildIDTokenClaims(api orchestrator.Orchestrator, _ *http.Request) (map[string]any, error) {
logger := api.Logger()
logger.Debug("se", "building ID token claims")
session, err := api.Session()
if err != nil {
logger.Error("se", "unable to retrieve session", "error", err.Error())
return nil, err
}
groups, err := session.GetString("okta.groups")
return map[string]any{
"groups": groups,
}, err
}