Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First Party SSO use case #25

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/scenarios/Use Case Patterns.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@startuml
'https://plantuml.com/sequence-diagram'

/' Should all sequence diagrams have a title? '/
title "Sequence Diagram Patterns"
/' Should we autonumber sequences? '/
autonumber

/' Should we encourage use of Participant commands? '/
participant "Browser" as UA
participant "Relying Party" as RP
participant "Identity Provider" as IDP

note across: Request/Response Pattern
UA ->o RP: Authentication Request
RP->UA: Authentication Response

/' Should we be explicit about redirects? '/
note across: Redirect Pattern
UA->RP: login
RP-->UA: redirect to IDP\nSet-Cookie: CSRF <value>
UA->IDP: /authorize

group iframe 1 [iframe from IDP]
IDP-->UA: load iframe to RP logout URL
UA->RP: /logout
RP->UA: Set-Cookie: <remove session cookie>\nreturn empty content
end
@enduml
108 changes: 108 additions & 0 deletions src/scenarios/oidc_first-party-sso.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
## OpenID Connect - First Party SSO
Web property with multiple services that all use the same identity provider.

### Summary

##### Contributor
- Name: George Fletcher
- Organization: Verizon Media
- Email: [email protected]

#### Protocol
- Name: OIDC
- Grant/flow (if applicable): AuthCode
- Reference: [aa](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth)

#### Browser Features Required
- 1st party Cookie
- 3rd party Cookie (cross-domain use case)
- Redirect with link decoration
- Local Storage
- JavaScript

##### Target Audience
B2C

#### Adoption
Unknown but I suspect this pattern is widely used.

### Description Of The Flow
Provide single-sign-on services across a set of web domains managed by the same company. Take for example a company named Acme that runs multiple services in different geographical locations with multiple domains: service1.acme.example, service2.acme.<country-domain>, service3.roadrunner.example. To manage the identity services across all these properties Acme runs idp.acme.example.

Using OpenID Connect (OIDC) Acme can allow each property to request the user to authenticate as needed, and the user's single authentication can be shared across all the different properties.

Generally, the user will visit a property (service1.acme.example) and either select the login option (or be immediately) redirected to idp.acme.example. As part of the HTTP redirect, service1.acme.example will set a cookie with an encrypted value containing the secret used to generate the OIDC state parameter (SHA256 has of the secret) and the value of the nonce parameter. This cookie should be explicitly set to samesite=lax and written on the service1.acme.example domain.

When the user arrives at the login page, idp.acme.example will determine if the user is already logged in and if so, immediately redirect the user to service1.acme.example with the OIDC authorization code and state values. If the user is not currently logged in, then the browser will display UI requesting the user to login. This UI uses Javascript to determine elements of the browser and possibly stored state. The user will be asked to enter their authentication credentials. Once the user has authenticated, the browser will be redirected to service1.acme.example with the authorization code and state values.

When service1.example.com receives the redirect from idp.acme.example, it will first look for the encrypted cookie value it wrote when requesting the user to authenticate. It will then validate the state value to ensure this redirect is coming from the same browser where the request was initiated. Service1.example.com will also extract the nonce value for comparison with the nonce in the id_token when it is retrieved. Note that if the state parameter validation fails, service1.acme.example will abort the authentication with an error.

The rest of the flow is standard OAuth/OpenID Connect for obtaining tokens and validating them (e.g. id_token nonce validation). Now that service1.acme.example has valid tokens and an authenticated user, it writes a session cookie on the services1.acme.example domain identifying the user who authenticated. This cookie should also be set with the samesite=lax attribute. Note that it is out of scope for this description as to how the authentication session is referenced in the service1 specific cookie. However, it is important to note that just writing the session cookie on the *.acme.example domain may not be desired because the allowed authorization access of the user at service1.acme.com may be different than the allowed authorization access at service4.acme.com.

#### Sequence Diagram
```
┌───────┐ ┌─────────────────────┐ ┌────────────────┐ ┌───────────────────────────┐
│browser│ │service1.acme.example│ │idp.acme.example│ │service3.roadrunner.example│
└───┬───┘ └──────────┬──────────┘ └───────┬────────┘ └─────────────┬─────────────┘
╔═════════╧═══════════════════════════╧═════════════════════════════╧═══════════════════════════════════╧═════════╗
║Sign-in Process ░║
╚═════════╤═══════════════════════════╤═════════════════════════════╤═══════════════════════════════════╤═════════╝
│ Click Sign-in Button │ │ │
│──────────────────────────>│ │ │
│ │ │ │
│[redirect] set CSRF cookie │ │ │
│samesite=lax │ │ │
│<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │ │
│ │ │ │
│ Start authentication │ │
│────────────────────────────────────────────────────────>│ │
│ │ │ │
│ │ │────┐
│ │ │ │ Is the user already logged in?
│ │ │<───┘
│ │ │ │
│ │ │ ╔═════════════════════════════╗ │
│ │ │ ║Validate User AuthN cookies ░║ │
│ │ │ ╚═════════════════════════════╝ │
│ │ │ │
╔══════╤══════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╗
║ ALT │ User is NOT logged in │ │ ║
╟──────┘ │ │ │ ║
║ │ Request user to authenticate │ ║
║ │<────────────────────────────────────────────────────────│ ║
║ │ │ │ ║
║ │ User credentials │ ║
║ │────────────────────────────────────────────────────────>│ ║
║ │ │ │ ║
║ │ │ │────┐ ║
║ │ │ │ │ Validate User credentials ║
║ │ │ │<───┘ ║
║ │ │ │ ║
║ │ [redirect] Set User AuthN cookies │ ║
║ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ ║
╠═════════════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╣
║ │ │ │ ║
║ │ [redirect] │ ║
║ │<─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ ║
╚═════════════╪═══════════════════════════╪═════════════════════════════╪═══════════════════════════════════╝
│ │ │ │
│Authorization Code + state │ │ │
│──────────────────────────>│ │ │
│ │ │ │
│ │ request tokens │ │
│ │────────────────────────────>│ │
│ │ │ │
│ │ access, refresh, id tokens │ │
│ │<────────────────────────────│ │
┌───┴───┐ ┌──────────┴──────────┐ ┌───────┴────────┐ ┌─────────────┴─────────────┐
│browser│ │service1.acme.example│ │idp.acme.example│ │service3.roadrunner.example│
└───────┘ └─────────────────────┘ └────────────────┘ └───────────────────────────┘
```
### Intended User Experience
The goal of this user experience is to allow the user to share their authentication across all the properties managed by Acme.

### Privacy Considerations
Since all parties involved in this flow are services offered by Acme, the user's privacy is covered under Acme's privacy policy.

### Miscellaneous
This flow description is just to cover the redirect aspect of the sign-in experience. Other use cases will cover additional aspect such as how the IDP can associate trust with the user's authentication request, or how to help the user address the NASCAR issue.
27 changes: 27 additions & 0 deletions src/scenarios/oidc_first-party-sso.puml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@startuml
Participant "browser" as B
Participant "service1.acme.example" as RP1
Participant "idp.acme.example" as IDP
Participant "service3.roadrunner.example" as RP2

note across
Sign-in Process
end note

B->RP1: Click Sign-in Button
RP1-->B: [redirect] set CSRF cookie\nsamesite=lax
B->IDP: Start authentication
IDP->IDP: Is the user already logged in?
note right of IDP: Validate User AuthN cookies
alt User is NOT logged in
IDP->B: Request user to authenticate
B->IDP: User credentials
IDP->IDP: Validate User credentials
IDP-->B: [redirect] Set User AuthN cookies
else
IDP-->B: [redirect]
end
B->RP1: Authorization Code + state
RP1->IDP: request tokens
IDP->RP1: access, refresh, id tokens
@enduml