5.9 KiB
+++ +++
ok let's dive in i guess
https://openid.net/developers/specs/
here's what i could grasp
spec summary
openid connect core (OIDC-CORE)
main points:
- use oauth 2 to issue an ID Token
- use jwt to construct specific claims
- the
iss
uer is the url of the IdP host - the
sub
ject is some unique identifier (uuid? etc) - the
aud
ience MUST contain theclient_id
and MAY be an array with other values - the
exp
iry is some unix timestamp (integer seconds since jan 1970) - the
iat
(issued at) is also a unix timestamp - the
auth_time
is a timestamp of when the user was authenticated- required for
max_age
or whenauth_time
is marked as "essential claim"
- required for
- the
nonce
is a string that mitigates replay attacks.- clients add this and you pass it back so they can verify
- required only if the client gives it to you, MUST be passed back as-is with no processing
- OPTIONAL: the
acr
(authentication class reference) indicates the "level"?? of the authentication. similar tonist_auth_level
in openid 2.0?-
Parties using this claim will need to agree upon the meanings of the values used, which may be context-specific
- so this is gonna require more in-depth investigation later
-
- OPTIONAL: the
amr
(authentication method reference) is an array of identifiers for which methods were used to authenticate -- password/otp/etc-
The definition of particular values to be used in the amr Claim is beyond the scope of this specification
- so this is also gonna need investigation later
-
- OPTIONAL: the
azp
is the authorized party, this MUST contain theclient_id
. only needed when theaud
is a single value that is different, but may be inclued even if it's the same. - OPTIONAL: you MAY include other claims other than the standardized ones above, or per other standards
- the
- use jws to sign the token (required) and jwe to encrypt the token (optional)
- sign, THEN encrypt, to produce a nested jwt as defined in the jwt spec
example: client s6BhdRkqt3
makes an authentication request n-0S6_WzA2Mj
, and gets a response that user 24400320
on https://server.example.com
was authenticated at 1311280970
and this claim expires in 1000 seconds
{
// the authority
"iss": "https://server.example.com",
"sub": "24400320",
// the request
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
// timestamps and ranges
"auth_time": 1311280969,
"iat": 1311280970,
"exp": 1311281970,
// some extra info about the authn level
"acr": "urn:mace:incommon:iap:silver"
}
three flows defined as part of oauth 2: response_type
==
code
for authorization code flow. code is returned from authorization endpoint, exchanged for token from token endpoint [best practice is to use this with PKCE]id_token
or bothid_token token
for implicit flow. allows one round-trip, but inherently insecure [deprecated in oauth 2.1 even]- hybrid flow? ask for some combo of
code
and at least one ofid_token
ortoken
.
also note that token
is defined in oauth 2 but not? used for oidc? since no IdT is returned
putting it all together?
per OIDC-DISCOVERY: webfinger? look for or query rel
link http://openid.net/specs/connect/1.0/issuer
and you obtain the host
{
"subject": "acct:joe@example.com", // or the url "https://example.com/joe" could work. more than one way to get to this point, in theory.
"links":
[
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://server.example.com" // bingo.
}
]
}
also per OIDC-DISCOVERY: obtain the openid configuration to get endpoints and relevant info
GET /.well-known/openid-configuration HTTP/1.1
Host: server.example.com
{
"issuer":
"https://server.example.com",
"authorization_endpoint":
"https://server.example.com/connect/authorize",
"token_endpoint":
"https://server.example.com/connect/token",
"registration_endpoint":
"https://server.example.com/connect/register",
// ...
}
register your client with Dynamic Client Registration (OIDC-DCR)
POST /connect/register HTTP/1.1
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ... # may be obtained out-of-band or otherwise dropped if you want anyone to be able to register
{
// ...
}
make a GET request following the authcode flow. scopes defined in OIDC-CORE, along with their associated claims:
- the
openid
scope grants standard claims likesub
and must be present to validate the auth request - the
profile
scope grants claims forname
family_name
given_name
middle_name
nickname
preferred_username
profile
picture
website
gender
birthdate
zoneinfo
locale
updated_at
- the
email
scope grants claims foremail
email_verified
- the
address
scope grants claims foraddress
- the
phone
scope grants claims forphone_number
phone_number_verified
[TODO: are there any standards for granular scopes or for information not in this list? i see FHIR for health information registries, like patient/*.* sens/ETH sens/PSY btg
to request access to all patient data with all methods, plus substance abuse and psychiatry data, while "breaking the glass" (the patient is unavailable, so log this in an audit log somewhere). so i'm guessing that i'm going to be firmly in extension territory here...]
also per OIDC-PROMPT-CREATE you may add prompt=create
to initiate a user registration?
GET /authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
exchange your code for a user token
POST /token?
// ...
drafts to consider (and their implications)
per OID4VP (verifiable presentations, related to verifiable credentials): you may have client_id == redirect_uri or you may have iss == aud. this indicates a self-issued token. maybe the value is a DID?