> ## Documentation Index
> Fetch the complete documentation index at: https://docs.strata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# SAML

SAML service extensions let you customize how the Orchestrator builds and delivers SAML assertions to your service providers. Use these hooks to control authentication, enforce authorization, load user attributes, customize assertion claims, and configure IdP-initiated single sign-on.

## Request Lifecycle

The SAML provider handles both service provider-initiated (SP-initiated) SSO and identity provider-initiated (IdP-initiated) SSO. Both flows use the same processing pipeline once the authentication request is established.

```mermaid theme={null}
%%{init: {'theme': 'neutral', 'themeVariables': {'edgeWidth': 4}}}%%
flowchart TD
    REQ{How was login started?}
    REQ -- SP-initiated --> PARSE[Validate authentication request]
    REQ -- IdP-initiated --> SYNTH[Build authentication request]
    SYNTH --> PARSE
    PARSE --> SESS[Establish session]
    SESS --> ISAUTH{isAuthenticatedSE}
    ISAUTH -- "true" --> LOADATTR[loadAttrsSE]
    ISAUTH -- "false" --> AUTH[authenticateSE]
    AUTH --> REDIR[Redirect to identity provider]
    LOADATTR -- error --> LERR[Return error]
    LOADATTR -- success --> AUTHZ{isAuthorizedSE}
    AUTHZ -- authorized --> CLAIMS[buildClaimsSE]
    AUTHZ -- denied --> DENY[Return error or 403]
    CLAIMS -- error --> CERR[Return error]
    CLAIMS -- success --> RELAY{IdP-initiated?}
    RELAY -- Yes --> RS[buildRelayStateSE]
    RELAY -- No --> RESP[Send SAML response to service provider]
    RS --> RESP[Send SAML response to service provider]

    classDef hook stroke:#6A3EC8,stroke-width:6px
    class ISAUTH,AUTH,LOADATTR,AUTHZ,CLAIMS,RS hook
```

For IdP-initiated login, the Orchestrator creates a synthetic AuthnRequest and processes it through the same pipeline as SP-initiated requests. The `buildRelayStateSE` hook is only called during IdP-initiated flows. The authorization step evaluates `isAuthorizedSE` if configured, along with any declarative authorization rules.

## Hooks

### `isAuthenticatedSE`

Determine whether the current user is already authenticated. Return `true` to skip the login flow, or `false` to send the user through authentication. Use this when you need custom logic to check authentication status -- for example, validating an external session token or checking a cookie from another system.

**Signature:**

```go theme={null}
func IsAuthenticated(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```

**Config location:** `apps[].authentication.isAuthenticatedSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer for the current request                              |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

**Returns:** `bool` -- `true` if the user is authenticated, `false` otherwise.

<Note>
  `isAuthenticatedSE` cannot be used together with the `idps` field on SAML apps.
</Note>

***

### `authenticateSE`

Handle authentication when the user has not yet logged in. Use this to redirect to an external login page, validate credentials directly, or start a custom authentication flow.

**Signature:**

```go theme={null}
func Authenticate(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request)
```

**Config location:** `apps[].authentication.authenticateSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer -- use to redirect or return an error response       |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

<Note>
  `authenticateSE` cannot be used together with the `idps` field on SAML apps.
</Note>

***

### `isAuthorizedSE`

Decide whether an authenticated user is allowed to proceed. Return `true` to allow the request or `false` to deny it. Use this to call an external policy engine, enforce attribute-based access control (ABAC), or apply custom business rules beyond what declarative authorization rules support.

**Signature:**

```go theme={null}
func IsAuthorized(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) bool
```

**Config location:** `apps[].authorization.isAuthorizedSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer for the current request                              |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

**Returns:** `bool` -- `true` if the user is authorized, `false` otherwise.

***

### `loadAttrsSE`

Enrich the user's session with additional attributes before the SAML assertion is built. Use this to pull in user details from external sources -- such as an LDAP directory, a database, or a REST API -- transform attribute values, or merge attributes from multiple identity providers.

**Signature:**

```go theme={null}
func LoadAttrs(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) error
```

**Config location:** `apps[].loadAttrsSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer for the current request                              |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

**Returns:** `error` -- return `nil` on success, or an error to indicate attribute loading failed.

***

### `buildClaimsSE`

Add custom attributes to SAML assertions sent to service providers. The attributes you return are included in the assertion's attribute statement alongside any standard attributes. Use this to include additional user data, transform values, or vary the attributes based on which service provider is requesting them.

**Signature:**

```go theme={null}
func BuildClaims(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) (map[string]any, error)
```

**Config location:** `apps[].buildClaimsSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer for the current request                              |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

**Returns:**

* `map[string]any` -- claims to include in the SAML assertion
* `error` -- return `nil` on success, or an error if claim building fails

***

### `buildRelayStateSE`

Set the RelayState value for IdP-initiated login flows. RelayState tells the service provider where to send the user after login -- for example, a specific landing page or deep link. Use this to dynamically determine the destination based on user attributes or request context.

**Signature:**

```go theme={null}
func BuildRelayState(api orchestrator.Orchestrator, rw http.ResponseWriter, req *http.Request) string
```

**Config location:** `apps[].idpInitiatedLogin.buildRelayStateSE`

**Parameters:**

| Parameter | Type                        | Description                                                                   |
| --------- | --------------------------- | ----------------------------------------------------------------------------- |
| `api`     | `orchestrator.Orchestrator` | Access to sessions, caches, secrets, logging, and other Orchestrator services |
| `rw`      | `http.ResponseWriter`       | The HTTP response writer for the current request                              |
| `req`     | `*http.Request`             | The incoming HTTP request                                                     |

**Returns:** `string` -- the RelayState value to include in the SAML response.

## Related Pages

<CardGroup cols={2}>
  <Card title="Service Extensions Overview" icon="code" href="/reference/orchestrator/service-extensions">
    Configuration, SDK reference, and best practices
  </Card>

  <Card title="SAML Applications" icon="building-shield" href="/reference/orchestrator/applications/saml">
    SAML application configuration and assertion settings
  </Card>
</CardGroup>
