11from typing import Any , Literal
22
3- from pydantic import AnyHttpUrl , BaseModel , Field
3+ from pydantic import AnyHttpUrl , BaseModel , Field , field_validator
44
55
66class OAuthToken (BaseModel ):
@@ -9,11 +9,20 @@ class OAuthToken(BaseModel):
99 """
1010
1111 access_token : str
12- token_type : Literal ["bearer " ] = "bearer "
12+ token_type : Literal ["Bearer " ] = "Bearer "
1313 expires_in : int | None = None
1414 scope : str | None = None
1515 refresh_token : str | None = None
1616
17+ @field_validator ('token_type' , mode = 'before' )
18+ @classmethod
19+ def normalize_token_type (cls , v : str | None ) -> str | None :
20+ if isinstance (v , str ):
21+ # Bearer is title-cased in the spec, so we normalize it
22+ # https://datatracker.ietf.org/doc/html/rfc6750#section-4
23+ return v .title ()
24+ return v
25+
1726
1827class InvalidScopeError (Exception ):
1928 def __init__ (self , message : str ):
@@ -111,13 +120,13 @@ class OAuthMetadata(BaseModel):
111120 token_endpoint : AnyHttpUrl
112121 registration_endpoint : AnyHttpUrl | None = None
113122 scopes_supported : list [str ] | None = None
114- response_types_supported : list [Literal ["code" ]] = ["code" ]
123+ response_types_supported : list [Literal ["code" ] | str ] = ["code" ]
115124 response_modes_supported : list [Literal ["query" , "fragment" ]] | None = None
116125 grant_types_supported : (
117- list [Literal ["authorization_code" , "refresh_token" ]] | None
126+ list [Literal ["authorization_code" , "refresh_token" ] | str ] | None
118127 ) = None
119128 token_endpoint_auth_methods_supported : (
120- list [Literal ["none" , "client_secret_post" ]] | None
129+ list [Literal ["none" , "client_secret_post" ] | str ] | None
121130 ) = None
122131 token_endpoint_auth_signing_alg_values_supported : None = None
123132 service_documentation : AnyHttpUrl | None = None
@@ -126,12 +135,12 @@ class OAuthMetadata(BaseModel):
126135 op_tos_uri : AnyHttpUrl | None = None
127136 revocation_endpoint : AnyHttpUrl | None = None
128137 revocation_endpoint_auth_methods_supported : (
129- list [Literal ["client_secret_post" ]] | None
138+ list [Literal ["client_secret_post" ] | str ] | None
130139 ) = None
131140 revocation_endpoint_auth_signing_alg_values_supported : None = None
132141 introspection_endpoint : AnyHttpUrl | None = None
133142 introspection_endpoint_auth_methods_supported : (
134- list [Literal ["client_secret_post" ]] | None
143+ list [Literal ["client_secret_post" ] | str ] | None
135144 ) = None
136145 introspection_endpoint_auth_signing_alg_values_supported : None = None
137- code_challenge_methods_supported : list [Literal ["S256" ]] | None = None
146+ code_challenge_methods_supported : list [Literal ["S256" ] | str ] | None = None
0 commit comments