In this article
1.1. Resource owner authorization
1.1.1. Authorization Code Grant type
1.1.1.1. Authorization request
1.1.3. Resource Owner Password Credentials Grant
1.2. Service level authorization
1.3. OAuth 2 API authorization - “Client credentials” grant
1.4. Structure of Passport’s auth_token's claims
2. Access to user's identity information
3. Obtain metadata of SSO Passport for a user
Revisions
Document Version |
Change Description |
Effective Date |
1.1 |
“іnvalidate” & “orgGuid” parameters are added for #1.1.1.1 & #1.1.2 |
Apr 03, 2020 |
1.0 |
“username” attribute added in response for #2 |
Aug 11, 2020 |
1. OAuth 2 authorization
GG4L provides its institutional tenants with the web-based Single Sign-On (SSO) Platform, called Passport. Each tenant can have its custom domain name for API and web-based UI (e.g. schoolA.edu, mydistrict.edu.ca, etc).
There are two distinct scenarios for integration that rely on Passport’s OAuth Identity Provider service:
-
“Login with Passport” is when a Service Provider (your application) allows users to authenticate using Passport’s OAuth service. Identity of Organization can be submitted when redirecting a user to Passport’s SSO Platform to eliminate the need for a user to select organization from UI of Passport (see API documentation for further details).
-
“Passport initiated SSO to a Service Provider” is when a user requests access to your service from Passport’s SSO Platform (being already authenticated in Passport). In a typical workflow, the Service Provider would provide an endpoint that redirects browser agent back to Passport’s OAuth service (as per #1.1.1.1 below, for example). This redirect should use the hostname of the originating SSO request (e.g. schoolA.edu or myschool.edu.ca etc). The Service Provider should derive the value of hostname from SSO request (either using “Referrer” header or Passport can include that value as a parameter). An alternative simplified workflow can be considered as well. For example, Passport can start SSO by sending OAuth code or OAuth access token.
-
By default, OAuth access_token is valid for 12 hours and refresh_token is valid for 30 days.
1.1 Resource owner authorization
1.1.1 Authorization Code Grant type
1.1.1.1 Authorization request
GET |
/account/default/authorize?response_type={responseType}&client_id={clientId}&redirect_uri={redirectUri} |
The endpoint to authenticate a user. Uses for login via OAuth. |
GET |
/oauth/auth?response_type={responseType}&client_id={clientId}&redirect_uri={redirectUri} |
The endpoint to authenticate a user. Uses for login thought ETX. |
Parameters:
Parameter |
Mode |
Type |
Description |
response_type |
Required |
String |
The type of the response (should be: code) |
client_id |
Required |
String |
OAuth client identifier registered with SSO Platform |
redirect_uri |
Required |
String |
The URI for redirection after successful authentication (the value should match one of the registered in SSO Platform) |
state |
Optional |
String |
This parameter will be returned to a requester after successful authentication of a user |
orgGuid |
Optional |
String |
An identifier of the organization (typically of a district). This value corresponds to the value of GUID that consumers of roster data receive from GG4L. GG4L will prepopulate “Organization selector” in the Login page based on the provided value of orgGuid. |
invalidate |
Optional |
boolean |
The default value is “false”. Set the value to “true” to invalidate any active web session and OAuth tokens associated with that session. |
prompt |
Optional |
String |
Set the value to “login” to invalidate any active web session. Refer to Learn more about OAuth2 Refresh Token. |
org_guid |
Optional |
String |
An identifier of the organization (typically of a district). This value corresponds to the value of GUID that consumers of roster data receive from GG4L. GG4L will prepopulate “Organization selector” in the Login page based on the provided value of orgGuid. |
Example of request (response_type=code):
https://{hostname}/oauth/auth?response_type=code&client_id={clientId}&redirect_uri=https://{partner’s_hostname}
Example of response (after successful authentication):
Redirect to redirect_uri (as provided in the request)
https://{partner’s_hostname}/?code=GmUGCD&state={state}
Errors:
Error message |
Code |
Description |
{redirectUri}?error=unsupported_response_type&error_description=Unsupported+response+types%3A+%5B{not_valid_response_type}%5D |
302 |
Response type is not valid or unsupported or missing |
{"error":"Client is not registered"} |
400 |
Client_id is not valid or not found |
{"error":"Invalid redirect: https://not_valid_uri does not match one of the registered values: [https://valid_uri]"} |
400 |
Redirect URI is not valid or not registered for specified client_id |
{"error":"A client id must be provided"} |
400 |
Client_id parameter is missing |
{"error":"A redirect_uri must be supplied."} |
400 |
Redirect_uri parameter is missing |
1.1.1.2 Access token request
POST |
/oauth/token?grant_type=authorization_code&code={code}&redirect_uri={redirect_uri} |
The endpoint to obtain access_token |
The request must contain WWW BASIC authorization with client_id and client secret key in the request header:
‘Authorization’: ‘Basic {data}’
where:
data = Base64.encode(‘{client_id}:{client secret}’)
Example:
Method |
POST |
URL |
https://{hostname}/oauth/token |
Body |
grant_type=authorization_code&code=GmUGCD&redirect_uri=https://{partner’s_hostname}/ |
Headers |
Authorization: Basic Y2xpZW50aWQ6Y2xpZW50c2VjcmV0 |
Response:
The API returns the following response on successful authentication:
{
"access_token": "...",
"token_type": "bearer",
"refresh_token": "...",
"expires_in": 43199,
"scope": "user.profile",
"auth_token": "..."
}
Field |
Type |
Description |
access_token | String | OAuth 2.0 Access Token |
token_type | String | Type of token - always bearer |
expires_in | Integer | Expiration time in seconds |
scope | String | An optional list with scopes that define granted data access |
state | String | The value provided in request |
auth_token | String | JWT Token with brief information about a user. Signature is created with secret key as per http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-07 |
refresh_token | String | OAuth 2.0 Refresh Token. Valid for 30 days (by default). |
Errors:
Error message |
Code |
Description |
{ "error":"invalid_grant", "error_description":"Unauthorized grant type: not_valid_grant"} |
400 |
Grant type is not valid |
{"error":"invalid_grant", |
400 |
Authorization code is not valid or used repeatedly |
{"error": "redirect_uri_mismatch", |
400 |
Redirect uri is not valid or not registered for specified client_id |
{"error":"authentication failed"} |
400 |
Client_id or client secret value or host parameter is not valid |
{"error":"invalid_request", |
400 |
Grant type parameter is missing |
{"error":"invalid_request", |
400 |
Code parameter is missing |
1.1.2. Implicit grant
GET |
/oauth/auth?response_type={responseType}&client_id={clientId}&redirect_uri={redirectUri} |
The endpoint to authenticate a user |
Parameters:
Parameter |
Mode |
Type |
Description |
sponse_type |
Required |
String |
The type of the response (should be: token) |
client_id |
Required |
String |
The identifier of the client registered on the server |
redirect_uri |
Required |
String |
The URI for redirection after successful authentication (the value gets validated if is registered in SSO Platform) |
state |
Optional |
String |
This parameter will be returned to requester after successful authentication of user |
orgGuid |
Optional |
String |
An identifier of the organization (typically of a district). This value corresponds to the value of GUID that consumers of roster data receive from GG4L. GG4L will prepopulate “Organization selector” in the Login page based on the provided value of orgGuid. |
іnvalidate |
Optional |
Boolean |
The default value is “false”. Set the value to “true” to invalidate any active web session and OAuth tokens associated with that session. |
prompt |
Optional |
String |
Set the value to “login” to invalidate any active web session. Learn more about OAuth2 Refresh Token |
org_guid |
Optional |
String |
An identifier of the organization (typically of a district). This value corresponds to the value of GUID that consumers of roster data receive from GG4L. GG4L will prepopulate “Organization selector” in the Login page based on the provided value of orgGuid. |
Example of request:
https://{hostname}/oauth/auth?response_type=token&client_id={clientId}&redirect_uri=https://{partner’s_hostname}
Response (after successful authentication):
redirect to redirect_uri (as provided in the request)
https://{partner’s_hostname}#access_token=...&token_type=bearer&expires_in=43199&scope={scopes}&auth_token=...
Field |
Type |
Description |
access_token |
String |
OAuth 2.0 Access Token |
token_type |
String |
Token's type. Always bearer |
expires_in |
Integer |
Expiration time in seconds |
scope |
String |
An optional list of scopes that define granted data access |
state |
String |
The value provided in request |
auth_token |
String |
Optional JWT Token with brief information about the user. Signature is created with a secret key as per OAuth JWT Assertion Profiles. |
Errors:
Error message |
Code |
Description |
{redirectUri}?error=unsupported_response_type&error_description=Unsupported+response+types%3A+%5B{not_valid_response_type}%5D |
302 |
Response type is not valid or unsupported or missing |
{"error":"Client is not registered"} |
400 |
Client_id is not valid or not found |
{"error":"Invalid redirect: https://not_valid_uri does not match one of the registered values: [https://valid_uri]"} |
400 |
Redirect URI is not valid or not registered for specified client_id |
{"error":"A client id must be provided"} |
400 |
Client_id parameter is missing |
{ "error":"A redirect_uri must be supplied."} |
400 |
Redirect_uri parameter is missing |
1.1.3. Resource Owner Password Credentials Grant
GET/ POST | /oauth/token?grant_type=password&username={username}&password={password}&_orgId={orgId} | The endpoint to authenticate a user |
The request must contain WWW BASIC authorization with client_id and client secret key in request header:
‘Authorization’: ‘Basic {data}’
where
data = Base64.encode(‘{client_id}:{client secret}’)
Parameters:
Parameter |
Mode |
Type |
Description |
grant_type |
Required |
String |
The type of the grant (should be: password) |
username |
Required |
String |
Credential username |
password |
Required |
String |
Credential password |
org_id |
Required |
String |
ID of organization hosted on SSO Platform |
Example of request:
https://{hostname}/oauth/token?grant_type=password&username=user1&password=1234&_orgId=123456
Response:
{
"access_token":"...",
"token_type":"bearer",
"refresh_token":"...",
"expires_in":43199,
"auth_token":"..."
}
1.2. Service level authorization
Where applications need to obtain an access_token without user interaction, application should provide a signed JWT.
POST |
/oauth/token |
The endpoint returns the access_token |
Parameters:
Parameter |
Mode |
Type |
Description |
auth_token |
Required |
String |
The signed JWT |
grant_type |
Required |
String |
Must be “jwt-bearer” |
Structure of JWT
Field |
Mode |
Description |
iss |
Required |
The issuer of the secret key. Must be "oauth.edutone.com" |
aud |
Required |
The hostname where JWT will be verified |
sub |
Required |
The client_id issued for secret key by SSO Passport |
exp |
Required |
The time window in seconds while token is valid |
iat |
Required |
The time in seconds from 1 Jan 1970 GMT when JWT is created |
pid |
Required/Optional |
The identifier of the user in SSO Passport for whom the access_token to be created. Should be provided for existing user and if prn value is not provided |
prn |
Required/Optional |
The email of the user for whom access_token to be created. Should be provided for existing user and if pid value is not provided. |
The following fields must be filed to create (if pid/prn aren’t provided) or update (if pid/prn are provided) an account on the fly. For an account creation all the “required” fields must be presented otherwise non personalized access_token is granted. For account update only new (not empty) field values must be provided. |
||
first |
Required/Optional |
First name |
last |
Required/Optional |
Last name |
|
Optional |
Email address |
school |
Required/Optional |
Identifier of the school associated with the user. Cannot be updated. |
role |
Required/Optional |
Role of the user |
type |
Required/Optional |
User's type - one of the following values: “school_admin”, ”teacher ”, ”student”,”parent”, “contact” |
external_id |
Required/Optional |
Identifier of the user in the external system (SIS/LMS etc). Used as a unique user’s key within school thus forbidding creation of accounts with the same external_id value. External ID is forbidden for update |
grade |
Optional |
Grade of the student (ignored for non “student” user types) - range of values from “-3” to “15” |
Response:
{
"access_token": "eyJraWQiOiIxIi...MbJ0Q",
"token_type": "Bearer",
"refresh_token": "2MLNxp6QiOiI...eP9gSlCi2LNxp6FaIg",
"expires_in": 300,
"scope": "profile",
"id_token": "eyJraWQiOiI...eP9gSlCi2MLNxp6FaIg"
}
Field |
Type |
Description |
access_token |
String |
OAuth 2.0 Access Token |
token_type |
String |
Type of token - always bearer |
expires_in |
Integer |
Expiration time in seconds |
scope |
String |
An optional list with scopes that define granted data access |
auth_token |
String |
Optional JWT Token with brief information about the user. Signature is created with secret key as per http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-07 |
refresh_token |
String |
OAuth2 Refresh Token. Valid for 30 days (by default) |
Errors:
Error message |
Code |
Description |
{"error":"untrusted issuer [iss=<...>]"} |
400 |
Issuer value differs from "oauth.edutone.com" |
{"error":"invalid client"} |
400 |
Client_id not found |
{"error":"invalid signature"} |
400 |
Invalid secret or invalid JWT signature |
{"error":"token has expired"} |
400 |
JWT token has expired |
{"error":"user not found"} |
400 |
User not found by pid or prn |
{"error":"insufficient jurisdiction”} |
400 |
User found but belongs to a different organization hierarchy |
{"error":"email address conflict”} |
400 |
More than one users found with provided prn address (within organization hierarchy) |
{"error":"uuid conflict”} |
400 |
More than one users found with provided pid (within organization hierarchy) |
1.3 OAuth 2 API authorization - “Client credentials” grant
The request must contain WWW BASIC authorization with client_id and client secret key in request header: ‘Authorization’: ‘Basic {data}’, where data = Base64.encode(‘{client_id}:{client secret}’)
With “client_credentials” OAuth grant type, a "userToken" parameter should be used when invoking Passport API in the context of a specific user account (for example, to retrieve user profile details or to invoke SSO etc). Contact GG4L for further information.
POST | /oauth/token | The endpoint returns the access_token |
Parameters:
Parameter |
Mode |
Type |
Description |
grant_type |
Required |
String |
Must be “client_credentials” |
Example:
Method | POST |
URL | /oauth/token HTTP/1.1 |
Host | host.gg4l.com |
Headers | Basic mF_9.B5f-4.1JqM |
Response (on successful authentication):
{
"access_token": "...",
"token_type": "bearer",
"refresh_token": "...",
"expires_in": 43199
}
Errors:
Error message |
Code |
Description |
{"error":"invalid_grant", "error_description":"Unauthorized grant type: not_valid_grant"} |
400 |
Grant type is not valid |
{"error":"authentication failed"} |
400 |
Client_id or client secret value or host parameter is not valid |
{"error":"invalid_request", |
400 |
Grant type parameter is missing |
1.4. Structure of Passport’s auth_token's claims
New attributes can be added to JSON response. Client side implementation should not rely on the order of the attributes.
JWT's claims:
{
"sub": "808980",
"ctx": "personal",
"roles": [
"TEACHER"
],
"iss": "https://sso.gg4l.com/account",
"client_id": "PTRYQPSEIH",
"aud": "PTRYQPSEIH",
"nbf": 1637782955,
"org_id": 348970,
"scope": "profile",
"username": "sslaylock",
"guid": "ff3801b6-3ac1-345d-7211-6dbe9213a233",
"exp": 1637784755,
"iat": 1637782955,
"jti": "cd4901c9-4ac0-475a-8a59-5dbe9213a00f"
}
Field |
Type |
Description |
iss |
String |
Unique identifier for the entity that issued the JWT - always “oauth.edutone.com” |
sub |
GUID |
Internal unique identifier of the user |
aud |
String |
Identifies the authorization server as an intended audience. The hostname that processed the request |
exp |
Integer |
Time window in seconds during which the JWT can be used |
iat |
Integer |
The time at which the JWT was issued (seconds from 1 Jan 1970) |
district |
GUID |
The unique id of user’s district in SSO Platform |
school |
GUID |
The unique id of user’s organization in SSO Platform |
type |
String |
User's type - one of the following values: “district_admin”, “school_admin”, ”teacher”, ”student”, “contact” |
last_modified |
BigInteger |
The time in seconds from 1 Jan 1970 GMT when attributes of the user were modified (reserved for future use) |
1.5. Refresh token
POST | /oauth/token | The endpoint returns the access_token |
The request must contain WWW BASIC authorization with client_id and client secret key in request header: ‘Authorization’: ‘Basic {data}’, where data = Base64.encode(‘{client_id}:{client secret}’)
Parameters:
Parameter |
Mode |
Type |
Description |
refresh_token |
Required |
String |
The refresh token value |
grant_type |
Required |
String |
Must be “refresh_token” |
Response:
{
"access_token": "...",
"token_type": "bearer",
"refresh_token": "...",
"expires_in": 43199,
"scope": "user.profile"
}
Field |
Type |
Description |
access_token |
String |
Token value that can be included in requests to API either as parameter “access_token” or as header “Authorization” (as per OAuth 2.0 specification). |
refresh_token |
String |
OAuth 2.0 Refresh Token |
token_type |
String |
Always “bearer” |
expires_in |
Integer |
Time window in seconds while access_token is valid |
scope |
String |
An optional list of scopes that define granted data access |
Errors:
Error message |
Code |
Description |
{"error":"invalid_grant", |
400 |
Grant type is not valid |
{"error":"Refresh token is mandatory"} |
400 |
Token value is not specified |
{"error":"authentication failed"} |
400 |
Client_id or client secret value or host parameter is not valid |
{"error":"invalid_request", |
400 |
Grant type parameter is missing |
{"error":"invalid_request"} |
Token value is not valid |
2. Access to user's identity information
New attributes can be added to JSON response. Client side implementation should not rely on the order of the attributes.
Additional data related to a user account (e.g. information about schools/sections/ students related to a teacher account) are available through Data API (documentation is available upon request).
GET | /services/v1.4/users/me | The endpoint returns identity information for a user account |
Access token to be supplied in authorization header as per RFC 6750
Response:
{
"data": {
"district": "4dff2226-er45-48c5-a9ef-82c529b02000",
"school": "332628ca-fghj-4291-8ddd-f4c31a05a032",
"id": "cba90bc1-941e-4247-uj89-288aca16500b",
"type": "student",
"email": "test@edutone.org",
"first": "First",
"last": "Last"
}
}
Field |
Type |
Description |
district |
GUID |
Identifier of the district associated with the user |
school |
GUID |
Identifier of the school associated with the user |
id |
GUID |
Identifier of the user in SSO Platform |
type |
String |
User's type - one of the following values: “district_admin”, “school_admin”, ”teacher ”, ”student”, “contact” |
|
String |
Email of the user |
first |
String |
First name of the user |
last |
String |
Last name of the user |
last_modified |
BigInteger |
The time in seconds from 1 Jan 1970 GMT when attributes of the user were modified (reserved for future use) |
Example:
Method | GET |
URL | /services/v1.4/users/me HTTP/1.1 |
Body | host.gg4l.com |
Headers |
Authorization: Bearer mF_9.B5f-4.1JqM |
Response:
{
"data": {
"district": "4dff2226-er45-48c5-a9ef-82c529b02000",
"school": "332628ca-fghj-4291-8ddd-f4c31a05a032",
"id": "cba90bc1-941e-4247-uj89-288aca1650bb",
"type": "student",
"email": "test@edutone.org",
"first": "First",
"last": "Last"
}
}
Errors:
Error message |
Code |
Description |
{"requestId":"id", |
400 |
Access token parameter is missing |
{"requestId":"id", |
400 |
Access token value is not valid |
{"requestId":"id", |
400 |
Access token value is expired |
3. Obtain metadata of SSO Passport for a user
3.1 Metadata for a User (Role)
New attributes can be added to JSON response. Client side implementation should not rely on the order of the attributes.
GET | /services/passport?ownerId={ownerId}access_token={valueOfAccessToken} | The endpoint to retrieve metadata about content of user's SSO Passport |
Response:
{
"ownerId": 2282419,
"children": [
{
"assetId": 564838,
"ownerId": 2282416,
"type": "FOLDER",
"parentId":,
"name": "School Resources",
"children": [
{
"assetId": 564844,
"ownerId": 2282416,
"type": "SSOLINK",
"parentId": 564838,
"name": "Curriki",
"children":,
"sizex": 2,
"sizey": 2,
"position": 1,
"image": "curriki.png",
"applicationId": "Curriki"
},
{
"assetId": 590744,
"ownerId": 2282416,
"type": "BKM",
"parentId": 564838,
"name": "Google",
"children":,
"url": "https://www.google.com",
"sizex": 2,
"sizey": 2,
"position": 2,
"image": "upload/2282412/ahCKGAjAWGDX.png"
}
],
"sizex": 2,
"sizey": 2,
"position": 1
}
],
"resourcesStorage": {
"baseUrl": "https://graphics.gg4l.com/p/content/images/"
}
}
Field |
Type |
Description |
assetId |
BigInteger |
A unique identifier of the asset |
ownerId |
BigInteger |
A unique identifier of the owner of the assets in SSO Passport. Owner of the asset has administrative rights on the respective asset. |
parentId |
BigInteger |
The unique identifier of the Asset that is a containers for the given resource |
type |
String |
The type of the Asset:
|
url |
String |
The URL of the Asset (applies to asset with the type of “BKM”) |
image |
String |
The URI of the image that represents an Asset in the Passport. Can be an absolute path or a value that needs to be concatenated with the value of “resourcesStorage” |
position |
Integer |
Used order of assets in layout of SSO Passport |
sizex |
Integer |
Horizontal size (relative units from 1 to 5) |
sizey |
Integer |
Vertical size (relative units from 1 to 5) |
Example:
https://{hostname}/services/passport?access_token=509615e8a-3ead-487d-afeb-01972c71e78b
Errors:
Error message |
Code |
Description |
{"requestId":"id", |
400 |
Access token parameter is missing |
{"requestId":"id", |
400 |
Access token value is not valid |
{"requestId":"id","messageId":"AccessTokenExpiredException", |
400 |
Access token value is expired |
4. Execute Single Sign-on
GET | /services/idm/sso/{applicationId}?access_token={valueOfAccessToken} | The endpoint to invoke Single Sign-on to the Application |
Parameters:
Parameter |
Mode |
Type |
Description |
applicationId |
required |
String |
The unique identifier of the Application |
Example:
https://{hostname}/services/idm/sso/PowerSchool?access_token=509615e8a-3ead-487d-afeb-01972c71e78b
Errors:
Error message |
Code |
Description |
{"requestId":"id", |
400 |
Access token parameter is missing |
{"requestId":"id","messageId":"AccessDeniedException", |
400 |
Access token value is not valid |
{"requestId":"id","messageId":"AccessTokenExpiredException", |
400 |
Access token value is expired |
{"error":"IdmObject doesn't exist [dname=invalid_applicationId]"} |
400 |
Application id value is not valid |
5. Log out
GET, POST | /oauth/loginwith/logout?redirect_uri={redirect_uri} | The endpoint logouts current user and performs redirecting to {redirect_uri} |
Parameters:
Parameter |
Mode |
Type |
Description |
redirect_uri |
Optional |
String |
The URL of external resource |
6. “Login with Google or Azure” functionality
A. "Login with Google or Azure" request to GG4L should contain OrgID.
B. "Login with Google or Azure" will be successful only for a user account that has email in GG4L address that matches G Suite or Azure AD account.
C. OAuth token gets returned immediately after authentication. Redirect_uri should be registered in GG4L.
6.1 Resource owner authorization
Method | GET |
Endpoint | /oauth/google/auth?school_guid={externalId}&client_id={clientId}&redirect_uri={redirectUri} |
Headers | The endpoint to authenticate a user via Google |
Method | GET |
Endpoint | /oauth/ad/auth?school_guid={externalId}&client_id={clientId}&redirect_uri={redirectUri} |
Headers | The endpoint to authenticate a user via Azure AD |
Parameter |
Mode |
Type |
Description |
school_guid |
optional/required |
String |
GG4L GUID of a school to which user belongs. Either school_guid or school_external_id is required. School_guid has preference over school_external_id. |
school_external_id |
optional/required |
String |
External Id of a school to which user belongs. Either school_guid or school_external_id is required. School_guid has preference over school_external_id. |
client_id |
required |
String |
OAuth client identifier registered with SSO Platform |
redirect_uri |
required |
String |
The URI to which authentication result is sent (the value should match one of the registered in SSO Platform). |
state |
optional |
String |
This parameter is returned back to a requester |
Example of request (response_type=code):
https://{hostname}/oauth/google/auth?school_external_id=332628ca-fghj-4291-8ddd-f4c31a05a032&client_id=clientId&redirect_uri=https://{partner’s_hostname}
Response:
The API returns the following response on successful authentication: redirect to redirect_uri (as provided in the request)
Errors:
Error message |
Code |
Description |
{"error":"Google/Azure user not found"} |
400 |
User has failed to login into Google or Azure |
{"error":"User not found"} |
400 |
Google or Azure AD account is not linked with ETA account |
{"error":"A school_guid or school_external_id must be supplied"} |
400 |
Either school_guid or school_external_id is required |
{"error":"School not found"} |
400 |
School not found by the specified school_guid and school_external_id |
{"error":"Client is not registered"} |
400 |
Client_id is not valid or not found |
{"error":"A client id must be provided"} |
400 |
Client_id parameter is missing |
{"error":"Invalid redirect: https://not_valid_uri does not match one of the registered values: [https://valid_uri]"} |
400 |
Redirect uri is not valid or not registered for the specified client_id |
{"error":"A redirect_uri must be supplied"} |
400 |
Redirect_uri parameter is missing |