Skip to content

Commit

Permalink
Merge pull request #37 from dudil/dudil/issue36
Browse files Browse the repository at this point in the history
Dudil/issue36
  • Loading branch information
dudil authored Apr 4, 2024
2 parents 802b265 + a0ff7ed commit f6d52af
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 54 deletions.
10 changes: 9 additions & 1 deletion fastapi_msal/models/base_auth_model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional, TypeVar

from pydantic import BaseModel, PrivateAttr
from pydantic import BaseModel, ConfigDict, PrivateAttr

from fastapi_msal.core import OptStrsDict, SessionManager, StrsDict

Expand All @@ -9,6 +9,14 @@

class BaseAuthModel(BaseModel):
_recieved: OptStrsDict = PrivateAttr(None)
model_config = ConfigDict(extra="allow")
"""
extra="allow"
for Pydantic to save additional fields that are not defined in the model.
Since the ID token can have additional fields defined in the app registration portal.
To access these fields (if any), use the `__pydantic_extra__` attribute of the object.
https://docs.pydantic.dev/latest/concepts/models/#extra-fields
"""

@classmethod
def parse_obj_debug(cls: type[AuthModel], to_parse: StrsDict) -> AuthModel:
Expand Down
74 changes: 40 additions & 34 deletions fastapi_msal/models/id_token_claims.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from fastapi_msal.core import MSALPolicies, OptStr, OptStrsDict

from .base_auth_model import BaseAuthModel
from .user_info import UserInfo


Expand Down Expand Up @@ -76,30 +77,19 @@ class AADInternalClaims(BaseModel):
"""


class IDTokenClaims(UserInfo, AADInternalClaims):
class IDTokenClaims(UserInfo, AADInternalClaims, BaseAuthModel):
"""
The ID token is a security token that contains claims about the authentication of an end-user by
an authorization server, when using a client, and potentially other requested claims.
The ID token is represented as a JSON Web Token (JWT).
For more information: https://learn.microsoft.com/en-us/entra/identity-platform/id-token-claims-reference
"""

exp: Optional[float] = None
"""
The expiration time claim is the time at which the token becomes invalid, represented in epoch time.
Your app should use this claim to verify the validity of the token lifetime.
"""

not_before: Optional[float] = Field(time.time() - 1, alias="nbf")
"""
This claim is the time at which the token becomes valid, represented in epoch time.
This is usually the same as the time the token was issued.
Your app should use this claim to verify the validity of the token lifetime.
"""

ver: OptStr = None
audience: Union[OptStr, list[str]] = Field(None, alias="aud")
"""
Indicates the version of the token.
An audience claim identifies the intended recipient of the token.
For Azure AD B2C, the audience is your app's Application ID, as assigned to your app in the app registration portal.
Your app should validate this value and reject the token if it does not match.
"""

issuer: OptStr = Field(None, alias="iss")
Expand All @@ -110,6 +100,11 @@ class IDTokenClaims(UserInfo, AADInternalClaims):
It also should use the GUID portion of the claim to restrict the set of tenants that can sign in to the app.
"""

issue_time: Optional[float] = Field(None, alias="iat")
"""
The time at which the token was issued, represented in epoch time.
"""

identity_provider: OptStr = Field(None, alias="idp")
"""
Records the identity provider that authenticated the subject of the token.
Expand All @@ -121,6 +116,19 @@ class IDTokenClaims(UserInfo, AADInternalClaims):
9188040d-6c67-4c5b-b112-36a304b66dad.
"""

not_before: Optional[float] = Field(time.time() - 1, alias="nbf")
"""
This claim is the time at which the token becomes valid, represented in epoch time.
This is usually the same as the time the token was issued.
Your app should use this claim to verify the validity of the token lifetime.
"""

exp: Optional[float] = None
"""
The expiration time claim is the time at which the token becomes invalid, represented in epoch time.
Your app should use this claim to verify the validity of the token lifetime.
"""

code_hash: OptStr = Field(None, alias="c_hash")
"""
The code hash is included in ID tokens only when the ID token is issued with an OAuth 2.0 authorization code.
Expand All @@ -141,6 +149,16 @@ class IDTokenClaims(UserInfo, AADInternalClaims):
This claim isn't returned on ID tokens from the /token endpoint.
"""

nonce: OptStr = None
"""
A nonce is a strategy used to mitigate token replay attacks.
Your app can specify a nonce in an authorization request by using the nonce query parameter.
The value you provide in the request will be emitted unmodified in the nonce claim of an ID token only.
This allows your app to verify the value against the value it specified on the request,
which associates the app's session with a given ID token.
Your app should perform this validation during the ID token validation process.
"""

subject: OptStr = Field(None, alias="sub")
"""
This is the principal about which the token asserts information, such as the user of an app.
Expand All @@ -158,27 +176,12 @@ class IDTokenClaims(UserInfo, AADInternalClaims):
the value is 9188040d-6c67-4c5b-b112-36a304b66dad.
"""

audience: Union[OptStr, list[str]] = Field(None, alias="aud")
"""
An audience claim identifies the intended recipient of the token.
For Azure AD B2C, the audience is your app's Application ID, as assigned to your app in the app registration portal.
Your app should validate this value and reject the token if it does not match.
"""

nonce: OptStr = None
ver: OptStr = None
"""
A nonce is a strategy used to mitigate token replay attacks.
Your app can specify a nonce in an authorization request by using the nonce query parameter.
The value you provide in the request will be emitted unmodified in the nonce claim of an ID token only.
This allows your app to verify the value against the value it specified on the request,
which associates the app's session with a given ID token.
Your app should perform this validation during the ID token validation process.
Indicates the version of the token.
"""

issue_time: Optional[float] = Field(None, alias="iat")
"""
The time at which the token was issued, represented in epoch time.
"""
#### Review the below claims if still needed

auth_time: Optional[float] = None
"""
Expand All @@ -190,9 +193,12 @@ class IDTokenClaims(UserInfo, AADInternalClaims):
This is the name of the policy that was used to acquire the token.
"""

### Private attributes

_id_token: Optional[str] = PrivateAttr(None)
"""
The raw id_token that was used to create this object - private attribute for internal use only
Will be set only via the `decode_id_token` method
"""

@staticmethod
Expand Down
65 changes: 46 additions & 19 deletions fastapi_msal/models/user_info.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,48 @@
from typing import Optional
from typing import Optional, Union

from pydantic import BaseModel, Field
from pydantic import Field

from fastapi_msal.core import OptStr, OptStrList
from fastapi_msal.core import OptStr, OptStrList, StrList

from .base_auth_model import BaseAuthModel

class UserInfo(BaseModel):
first_name: OptStr = Field(None, alias="given_name")

class UserInfo(BaseAuthModel):
preferred_username: OptStr = None
"""
The user's given name (also known as first name).
The primary username that represents the user.
It could be an email address, phone number, or a generic username without a specified format.
Its value is mutable and might change over time.
Since it is mutable, this value must not be used to make authorization decisions.
It can be used for username hints, however, and in human-readable UI as a username.
The profile scope is required in order to receive this claim. Present only in v2.0 tokens.
"""

last_name: OptStr = Field(None, alias="family_name")
email: OptStr = None
"""
The user's surname (also known as last name).
Present by default for guest accounts that have an email address.
Your app can request the email claim for managed users (from the same tenant) using the email optional claim.
This value isn't guaranteed to be correct and is mutable over time.
Never use it for authorization or to save data for a user.
On the v2.0 endpoint, your app can also request the email OpenID Connect scope -
you don't need to request both the optional claim and the scope to get the claim.
"""

display_name: OptStr = Field(None, alias="name")
"""
The user's full name in displayable form including all name parts, possibly including titles and suffixes.
The name claim provides a human-readable value that identifies the subject of the token.
The value isn't guaranteed to be unique, it can be changed, and should be used only for display purposes.
The profile scope is required to receive this claim.
"""

first_name: OptStr = Field(None, alias="given_name")
"""
The user's given name (also known as first name).
"""

last_name: OptStr = Field(None, alias="family_name")
"""
The user's surname (also known as last name).
"""

city: OptStr = None
Expand Down Expand Up @@ -58,16 +82,6 @@ class UserInfo(BaseModel):
The Microsoft Graph will return this ID as the id property for a given user account.
"""

preferred_username: OptStr = None
"""
The primary username that represents the user.
It could be an email address, phone number, or a generic username without a specified format.
Its value is mutable and might change over time.
Since it is mutable, this value must not be used to make authorization decisions.
It can be used for username hints, however, and in human-readable UI as a username.
The profile scope is required in order to receive this claim. Present only in v2.0 tokens.
"""

unique_name: OptStr = None
"""
Only present in v1.0 tokens. Provides a human readable value that identifies the subject of the token.
Expand All @@ -93,3 +107,16 @@ class UserInfo(BaseModel):
Indicates that the client should use the Microsoft Graph API to determine the user's groups
(https://graph.microsoft.com/v1.0/users/{userID}/getMemberObjects).
"""

groups: Union[StrList, str, None] = None
"""
Provides object IDs that represent the group memberships of the subject.
The groupMembershipClaims property of the application manifest configures the groups claim on a per-application basis.
A value of null excludes all groups, a value of SecurityGroup includes only Active Directory Security Groups,
and a value of All includes both Security Groups and Microsoft 365 Distribution Lists.
See the hasgroups claim for details on using the groups claim with the implicit grant. For other flows,
if the number of groups the user is in goes over 150 for SAML and 200 for JWT,
then Microsoft Entra ID adds an overage claim to the claim sources.
The claim sources point to the Microsoft Graph endpoint that contains the list of groups for the user.
"""

0 comments on commit f6d52af

Please sign in to comment.