Skip to content
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
12 changes: 7 additions & 5 deletions fosite/handler/openid/strategy_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ package openid

import (
"context"
"slices"
"strconv"
"strings"
"time"

"github.com/ory/x/errorsx"
Expand Down Expand Up @@ -157,20 +159,20 @@ func (h DefaultStrategy) GenerateIDToken(ctx context.Context, lifespan time.Dura
}
}

prompt := requester.GetRequestForm().Get("prompt")
if prompt != "" {
prompts := fosite.RemoveEmpty(strings.Split(requester.GetRequestForm().Get("prompt"), " "))
if len(prompts) > 0 {
if claims.AuthTime.IsZero() {
return "", errorsx.WithStack(fosite.ErrServerError.WithDebug("Unable to determine validity of prompt parameter because auth_time is missing in id token claims."))
}
}

switch prompt {
case "none":
if slices.Contains(prompts, "none") {
if !claims.AuthTime.Equal(claims.RequestedAt) && claims.AuthTime.After(claims.RequestedAt) {
return "", errorsx.WithStack(fosite.ErrServerError.
WithDebugf("Failed to generate id token because prompt was set to 'none' but auth_time ('%s') happened after the authorization request ('%s') was registered, indicating that the user was logged in during this request which is not allowed.", claims.AuthTime, claims.RequestedAt))
}
case "login":
}
if slices.Contains(prompts, "login") {
if !claims.AuthTime.Equal(claims.RequestedAt) && claims.AuthTime.Before(claims.RequestedAt) {
return "", errorsx.WithStack(fosite.ErrServerError.
WithDebugf("Failed to generate id token because prompt was set to 'login' but auth_time ('%s') happened before the authorization request ('%s') was registered, indicating that the user was not re-authenticated which is forbidden.", claims.AuthTime, claims.RequestedAt))
Expand Down
30 changes: 30 additions & 0 deletions fosite/handler/openid/strategy_jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,36 @@ func TestJWTStrategy_GenerateIDToken(t *testing.T) {
},
expectErr: true,
},
{
description: "should pass because prompt=select_account consent is valid space-separated per OIDC spec",
setup: func() {
req = fosite.NewAccessRequest(&openid.DefaultSession{
Claims: &jwt.IDTokenClaims{
Subject: "peter",
AuthTime: time.Now().Add(-time.Hour).UTC(),
RequestedAt: time.Now().Add(-time.Minute),
},
Headers: &jwt.Headers{},
})
req.Form.Set("prompt", "select_account consent")
},
expectErr: false,
},
{
description: "should fail because prompt includes login in space-separated list and auth_time indicates old login",
setup: func() {
req = fosite.NewAccessRequest(&openid.DefaultSession{
Claims: &jwt.IDTokenClaims{
Subject: "peter",
AuthTime: time.Now().Add(-time.Hour).UTC(),
RequestedAt: time.Now().Add(-time.Minute),
},
Headers: &jwt.Headers{},
})
req.Form.Set("prompt", "login consent")
},
expectErr: true,
},
{
description: "should pass because id_token_hint subject matches subject from claims",
setup: func() {
Expand Down
28 changes: 28 additions & 0 deletions fosite/handler/openid/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,34 @@ func TestValidatePrompt(t *testing.T) {
},
},
},
{
d: "should pass because select_account consent is a valid space-separated prompt per OIDC spec",
prompt: "select_account consent",
isPublic: false,
expectErr: false,
s: &openid.DefaultSession{
Subject: "foo",
Claims: &jwt.IDTokenClaims{
Subject: "foo",
RequestedAt: time.Now().UTC(),
AuthTime: time.Now().UTC().Add(-time.Minute),
},
},
},
{
d: "should pass because select_account consent works with public clients",
prompt: "select_account consent",
isPublic: true,
expectErr: false,
s: &openid.DefaultSession{
Subject: "foo",
Claims: &jwt.IDTokenClaims{
Subject: "foo",
RequestedAt: time.Now().UTC(),
AuthTime: time.Now().UTC().Add(-time.Minute),
},
},
},
{
d: "should pass because requesting consent and login works with confidential clients",
prompt: "login consent",
Expand Down
Loading