OAuth 2.0 und JWT in ABAP Cloud: Token-basierte Authentifizierung

kategorie
Security
Veröffentlicht
autor
Johannes

OAuth 2.0 und JWT (JSON Web Tokens) sind die Standard-Authentifizierungsmechanismen für moderne Cloud-Anwendungen. In ABAP Cloud ermöglichen sie sichere Service-zu-Service-Kommunikation und Benutzerauthentifizierung ohne Passwörter im Code.

Grundkonzepte

OAuth 2.0 Übersicht

OAuth 2.0 ist ein Autorisierungsframework, das Anwendungen kontrollierten Zugriff auf Ressourcen ermöglicht:

BegriffBeschreibung
Resource OwnerDer Benutzer oder System, dem die Ressource gehört
ClientDie Anwendung, die Zugriff anfordert (z.B. ABAP Cloud)
Authorization ServerStellt Access Tokens aus (z.B. XSUAA)
Resource ServerHostet die geschützte API
Access TokenKurzlebiges Token für API-Zugriff
Refresh TokenLanglebiges Token zur Token-Erneuerung

JWT (JSON Web Token)

JWT ist das Token-Format, das von OAuth 2.0 verwendet wird:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ1c2VyMTIzIiwiYXVkIjoibXktYXBwIiwiaXNzIjoieHN1YWEifQ.
signature_here

Ein JWT besteht aus drei Teilen (Base64-kodiert, durch Punkte getrennt):

TeilInhalt
HeaderAlgorithmus und Token-Typ
PayloadClaims (Benutzer-ID, Scopes, Ablaufzeit)
SignatureKryptografische Signatur zur Verifizierung

Wichtige JWT Claims

ClaimBeschreibung
subSubject - Benutzer- oder Client-ID
audAudience - Zielgruppe des Tokens
issIssuer - Aussteller (z.B. XSUAA-URL)
expExpiration - Ablaufzeitpunkt (Unix Timestamp)
iatIssued At - Ausstellungszeitpunkt
scopeBerechtigungsscopes
zidZone ID - Tenant-Identifier

OAuth 2.0 Flows

Client Credentials Flow

Der Client Credentials Flow wird für Service-zu-Service-Kommunikation verwendet, wenn kein Benutzer involviert ist:

┌─────────────────────────────────────────────────────────────────────────┐
│ Client Credentials Flow │
│ │
│ ┌─────────────┐ ┌─────────────────────┐ │
│ │ ABAP Cloud │ │ XSUAA │ │
│ │ (Client) │ │ (Auth Server) │ │
│ └──────┬──────┘ └──────────┬──────────┘ │
│ │ │ │
│ │ 1. POST /oauth/token │ │
│ │ grant_type=client_credentials │ │
│ │ client_id=xxx │ │
│ │ client_secret=yyy │ │
│ │────────────────────────────────────────────────>│ │
│ │ │ │
│ │ 2. Access Token (JWT) │ │
│ │<────────────────────────────────────────────────│ │
│ │ │ │
│ ┌──────┴──────┐ ┌──────────┴──────────┐ │
│ │ ABAP Cloud │ │ Resource Server │ │
│ │ (Client) │ │ (API) │ │
│ └──────┬──────┘ └──────────┬──────────┘ │
│ │ │ │
│ │ 3. API Call mit Bearer Token │ │
│ │ Authorization: Bearer <token> │ │
│ │────────────────────────────────────────────────>│ │
│ │ │ │
│ │ 4. API Response │ │
│ │<────────────────────────────────────────────────│ │
└─────────────────────────────────────────────────────────────────────────┘

Anwendungsfälle:

  • Backend-zu-Backend-Kommunikation
  • Batch-Jobs ohne Benutzerkontext
  • Technische Integrationsszenarien

Authorization Code Flow

Der Authorization Code Flow wird verwendet, wenn ein Benutzer beteiligt ist:

┌─────────────────────────────────────────────────────────────────────────┐
│ Authorization Code Flow │
│ │
│ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ Browser │ │ ABAP Cloud │ │ XSUAA │ │ Resource API │ │
│ └────┬────┘ └──────┬──────┘ └──────┬──────┘ └───────┬──────┘ │
│ │ │ │ │ │
│ │ 1. Login │ │ │ │
│ │───────────────>│ │ │ │
│ │ │ │ │ │
│ │ 2. Redirect zu │ │ │ │
│ │ XSUAA │ │ │ │
│ │<───────────────│ │ │ │
│ │ │ │ │
│ │ 3. Login-Seite │ │ │
│ │──────────────────────────────────>│ │ │
│ │ │ │ │
│ │ 4. Redirect mit Authorization Code│ │ │
│ │<──────────────────────────────────│ │ │
│ │ │ │ │ │
│ │ 5. Code │ │ │ │
│ │───────────────>│ │ │ │
│ │ │ 6. Token Request │ │ │
│ │ │─────────────────>│ │ │
│ │ │ 7. Access Token │ │ │
│ │ │<─────────────────│ │ │
│ │ │ │ │ │
│ │ │ 8. API Call │ │ │
│ │ │─────────────────────────────────────>│ │
│ │ │ 9. Response │ │ │
│ │ │<─────────────────────────────────────│ │
└─────────────────────────────────────────────────────────────────────────┘

Anwendungsfälle:

  • Web-Anwendungen mit Benutzer-Login
  • Single Sign-On (SSO)
  • Fiori-Anwendungen

XSUAA in SAP BTP

XSUAA (Extended Services for User Account and Authentication) ist der zentrale OAuth 2.0-Server auf SAP BTP:

XSUAA-Architektur

┌─────────────────────────────────────────────────────────────────────────┐
│ SAP BTP Subaccount │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ XSUAA Service │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ │ │
│ │ │ Identity │ │ Token │ │ Scope/Role │ │ │
│ │ │ Management │ │ Issuance │ │ Management │ │ │
│ │ │ - Shadow Users │ │ - JWT Signing │ │ - Role Templates │ │ │
│ │ │ - IDP Trust │ │ - Token Cache │ │ - Role Collections │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐ │
│ │ ABAP Cloud App │ │ CAP Application │ │ UI5 Application │ │
│ │ │ │ │ │ │ │
│ │ Service Binding: │ │ Service Binding: │ │ xs-app.json │ │
│ │ XSUAA │ │ XSUAA │ │ OAuth2 Route │ │
│ └───────────────────┘ └───────────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘

XSUAA Service Binding in ABAP Cloud

Die XSUAA-Credentials werden über ein Service Binding bereitgestellt:

CLASS zcl_xsuaa_config DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_xsuaa_credentials,
clientid TYPE string,
clientsecret TYPE string,
url TYPE string,
token_url TYPE string,
END OF ty_xsuaa_credentials.
CLASS-METHODS:
get_credentials
RETURNING VALUE(rs_credentials) TYPE ty_xsuaa_credentials
RAISING cx_abap_context_info_error.
ENDCLASS.
CLASS zcl_xsuaa_config IMPLEMENTATION.
METHOD get_credentials.
" XSUAA Credentials aus Service Binding lesen
" Diese werden vom System automatisch injiziert
DATA(lo_service_manager) = cl_ams_service_manager=>get_instance( ).
DATA(ls_binding) = lo_service_manager->get_service_binding(
iv_service_type = 'xsuaa'
).
" Credentials extrahieren
rs_credentials-clientid = ls_binding-credentials-clientid.
rs_credentials-clientsecret = ls_binding-credentials-clientsecret.
rs_credentials-url = ls_binding-credentials-url.
rs_credentials-token_url = |{ ls_binding-credentials-url }/oauth/token|.
ENDMETHOD.
ENDCLASS.

Token abrufen mit Client Credentials

OAuth 2.0 Token Request

CLASS zcl_oauth_client DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_token_response,
access_token TYPE string,
token_type TYPE string,
expires_in TYPE i,
scope TYPE string,
END OF ty_token_response.
METHODS:
constructor
IMPORTING is_credentials TYPE zcl_xsuaa_config=>ty_xsuaa_credentials,
get_access_token
RETURNING VALUE(rv_token) TYPE string
RAISING cx_web_http_client_error.
PRIVATE SECTION.
DATA ms_credentials TYPE zcl_xsuaa_config=>ty_xsuaa_credentials.
DATA ms_token_cache TYPE ty_token_response.
DATA mv_token_expiry TYPE timestamp.
METHODS:
request_new_token
RETURNING VALUE(rs_token) TYPE ty_token_response
RAISING cx_web_http_client_error,
is_token_valid
RETURNING VALUE(rv_valid) TYPE abap_bool.
ENDCLASS.
CLASS zcl_oauth_client IMPLEMENTATION.
METHOD constructor.
ms_credentials = is_credentials.
ENDMETHOD.
METHOD get_access_token.
" Token aus Cache verwenden wenn noch gueltig
IF is_token_valid( ) = abap_true.
rv_token = ms_token_cache-access_token.
RETURN.
ENDIF.
" Neuen Token anfordern
ms_token_cache = request_new_token( ).
" Ablaufzeit berechnen (mit 60 Sekunden Puffer)
GET TIME STAMP FIELD DATA(lv_now).
mv_token_expiry = cl_abap_tstmp=>add(
tstmp = lv_now
secs = ms_token_cache-expires_in - 60
).
rv_token = ms_token_cache-access_token.
ENDMETHOD.
METHOD request_new_token.
" HTTP Client fuer Token-Endpoint erstellen
DATA(lo_destination) = cl_http_destination_provider=>create_by_url(
i_url = ms_credentials-token_url
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
DATA(lo_request) = lo_client->get_http_request( ).
" Basic Authentication fuer Client Credentials
DATA(lv_auth_string) = |{ ms_credentials-clientid }:{ ms_credentials-clientsecret }|.
DATA(lv_auth_base64) = cl_web_http_utility=>encode_base64( lv_auth_string ).
lo_request->set_header_field(
i_name = 'Authorization'
i_value = |Basic { lv_auth_base64 }|
).
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/x-www-form-urlencoded'
).
" Token Request Body
lo_request->set_text( 'grant_type=client_credentials' ).
" Request ausfuehren
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
DATA(lv_status) = lo_response->get_status( )-code.
IF lv_status <> 200.
lo_client->close( ).
RAISE EXCEPTION TYPE cx_web_http_client_error.
ENDIF.
" Response parsen
DATA(lv_json) = lo_response->get_text( ).
lo_client->close( ).
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = rs_token
).
ENDMETHOD.
METHOD is_token_valid.
IF ms_token_cache-access_token IS INITIAL.
rv_valid = abap_false.
RETURN.
ENDIF.
GET TIME STAMP FIELD DATA(lv_now).
rv_valid = xsdbool( lv_now < mv_token_expiry ).
ENDMETHOD.
ENDCLASS.

Token mit Communication Arrangement

In produktiven Szenarien sollten Communication Arrangements verwendet werden:

CLASS zcl_oauth_comm_arrangement DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
call_protected_api
IMPORTING iv_path TYPE string
RETURNING VALUE(rv_response) TYPE string
RAISING cx_web_http_client_error
cx_http_dest_provider_error.
ENDCLASS.
CLASS zcl_oauth_comm_arrangement IMPLEMENTATION.
METHOD call_protected_api.
" Destination mit OAuth 2.0 Client Credentials aus Communication Arrangement
" Die Destination uebernimmt Token-Management automatisch
DATA(lo_destination) = cl_http_destination_provider=>create_by_comm_arrangement(
comm_scenario = 'Z_EXTERNAL_API'
service_id = 'Z_EXT_API_REST'
comm_system_id = 'EXT_SYSTEM'
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( iv_path ).
" Token wird automatisch durch die Destination hinzugefuegt
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
rv_response = lo_response->get_text( ).
lo_client->close( ).
ENDMETHOD.
ENDCLASS.

JWT Token Validierung

Token-Struktur parsen

CLASS zcl_jwt_parser DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_jwt_header,
alg TYPE string,
typ TYPE string,
kid TYPE string,
END OF ty_jwt_header,
BEGIN OF ty_jwt_payload,
sub TYPE string,
aud TYPE string,
iss TYPE string,
exp TYPE i,
iat TYPE i,
scope TYPE string,
zid TYPE string,
client_id TYPE string,
END OF ty_jwt_payload,
BEGIN OF ty_jwt_parts,
header TYPE ty_jwt_header,
payload TYPE ty_jwt_payload,
signature TYPE string,
END OF ty_jwt_parts.
METHODS:
parse
IMPORTING iv_token TYPE string
RETURNING VALUE(rs_parts) TYPE ty_jwt_parts
RAISING cx_abap_invalid_value.
PRIVATE SECTION.
METHODS:
decode_base64url
IMPORTING iv_encoded TYPE string
RETURNING VALUE(rv_decoded) TYPE string.
ENDCLASS.
CLASS zcl_jwt_parser IMPLEMENTATION.
METHOD parse.
" Token in drei Teile splitten
SPLIT iv_token AT '.' INTO DATA(lv_header_b64)
DATA(lv_payload_b64)
DATA(lv_signature).
IF lv_header_b64 IS INITIAL OR lv_payload_b64 IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.
" Header dekodieren und parsen
DATA(lv_header_json) = decode_base64url( lv_header_b64 ).
/ui2/cl_json=>deserialize(
EXPORTING json = lv_header_json
CHANGING data = rs_parts-header
).
" Payload dekodieren und parsen
DATA(lv_payload_json) = decode_base64url( lv_payload_b64 ).
/ui2/cl_json=>deserialize(
EXPORTING json = lv_payload_json
CHANGING data = rs_parts-payload
).
rs_parts-signature = lv_signature.
ENDMETHOD.
METHOD decode_base64url.
" Base64URL zu Standard Base64 konvertieren
DATA(lv_base64) = iv_encoded.
REPLACE ALL OCCURRENCES OF '-' IN lv_base64 WITH '+'.
REPLACE ALL OCCURRENCES OF '_' IN lv_base64 WITH '/'.
" Padding hinzufuegen falls noetig
DATA(lv_padding) = strlen( lv_base64 ) MOD 4.
IF lv_padding > 0.
lv_base64 = lv_base64 && repeat( val = '=' occ = 4 - lv_padding ).
ENDIF.
" Base64 dekodieren
rv_decoded = cl_web_http_utility=>decode_base64( lv_base64 ).
ENDMETHOD.
ENDCLASS.

Token-Validierung implementieren

CLASS zcl_jwt_validator DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_validation_result,
valid TYPE abap_bool,
error_msg TYPE string,
jwt_payload TYPE zcl_jwt_parser=>ty_jwt_payload,
END OF ty_validation_result.
METHODS:
constructor
IMPORTING iv_expected_issuer TYPE string
iv_expected_audience TYPE string,
validate
IMPORTING iv_token TYPE string
RETURNING VALUE(rs_result) TYPE ty_validation_result.
PRIVATE SECTION.
DATA mv_expected_issuer TYPE string.
DATA mv_expected_audience TYPE string.
METHODS:
validate_expiration
IMPORTING iv_exp TYPE i
RETURNING VALUE(rv_valid) TYPE abap_bool,
validate_issuer
IMPORTING iv_issuer TYPE string
RETURNING VALUE(rv_valid) TYPE abap_bool,
validate_audience
IMPORTING iv_audience TYPE string
RETURNING VALUE(rv_valid) TYPE abap_bool.
ENDCLASS.
CLASS zcl_jwt_validator IMPLEMENTATION.
METHOD constructor.
mv_expected_issuer = iv_expected_issuer.
mv_expected_audience = iv_expected_audience.
ENDMETHOD.
METHOD validate.
DATA(lo_parser) = NEW zcl_jwt_parser( ).
TRY.
DATA(ls_jwt) = lo_parser->parse( iv_token ).
CATCH cx_abap_invalid_value.
rs_result-valid = abap_false.
rs_result-error_msg = 'Invalid token format'.
RETURN.
ENDTRY.
" 1. Ablaufzeit pruefen
IF validate_expiration( ls_jwt-payload-exp ) = abap_false.
rs_result-valid = abap_false.
rs_result-error_msg = 'Token expired'.
RETURN.
ENDIF.
" 2. Issuer pruefen
IF validate_issuer( ls_jwt-payload-iss ) = abap_false.
rs_result-valid = abap_false.
rs_result-error_msg = |Invalid issuer: { ls_jwt-payload-iss }|.
RETURN.
ENDIF.
" 3. Audience pruefen
IF validate_audience( ls_jwt-payload-aud ) = abap_false.
rs_result-valid = abap_false.
rs_result-error_msg = |Invalid audience: { ls_jwt-payload-aud }|.
RETURN.
ENDIF.
" Token ist gueltig
rs_result-valid = abap_true.
rs_result-jwt_payload = ls_jwt-payload.
ENDMETHOD.
METHOD validate_expiration.
" Unix Timestamp in ABAP Timestamp konvertieren
DATA(lv_exp_ts) = cl_abap_tstmp=>utclong_unix_from_i( iv_exp ).
GET TIME STAMP FIELD DATA(lv_now).
rv_valid = xsdbool( lv_now < lv_exp_ts ).
ENDMETHOD.
METHOD validate_issuer.
rv_valid = xsdbool( iv_issuer CS mv_expected_issuer ).
ENDMETHOD.
METHOD validate_audience.
rv_valid = xsdbool( iv_audience = mv_expected_audience ).
ENDMETHOD.
ENDCLASS.

Eingehende Requests authentifizieren

Wenn Ihre ABAP Cloud-Anwendung als Resource Server agiert:

JWT aus HTTP Request extrahieren

CLASS zcl_request_authenticator DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
authenticate_request
IMPORTING io_request TYPE REF TO if_web_http_request
RETURNING VALUE(rs_result) TYPE zcl_jwt_validator=>ty_validation_result.
PRIVATE SECTION.
METHODS:
extract_bearer_token
IMPORTING io_request TYPE REF TO if_web_http_request
RETURNING VALUE(rv_token) TYPE string.
ENDCLASS.
CLASS zcl_request_authenticator IMPLEMENTATION.
METHOD authenticate_request.
" Bearer Token aus Authorization Header extrahieren
DATA(lv_token) = extract_bearer_token( io_request ).
IF lv_token IS INITIAL.
rs_result-valid = abap_false.
rs_result-error_msg = 'No Bearer token provided'.
RETURN.
ENDIF.
" Token validieren
DATA(lo_validator) = NEW zcl_jwt_validator(
iv_expected_issuer = 'https://mysubaccount.authentication.eu10.hana.ondemand.com'
iv_expected_audience = 'my-application-clientid'
).
rs_result = lo_validator->validate( lv_token ).
ENDMETHOD.
METHOD extract_bearer_token.
DATA(lv_auth_header) = io_request->get_header_field( 'Authorization' ).
IF lv_auth_header CP 'Bearer *'.
rv_token = lv_auth_header+7. " 'Bearer ' = 7 Zeichen
ENDIF.
ENDMETHOD.
ENDCLASS.

Scope-basierte Autorisierung

CLASS zcl_scope_authorizer DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
METHODS:
has_scope
IMPORTING iv_scope_string TYPE string
iv_required_scope TYPE string
RETURNING VALUE(rv_has_scope) TYPE abap_bool,
check_scope
IMPORTING iv_scope_string TYPE string
iv_required_scope TYPE string
RAISING zcx_not_authorized.
ENDCLASS.
CLASS zcl_scope_authorizer IMPLEMENTATION.
METHOD has_scope.
" Scopes sind space-separated
SPLIT iv_scope_string AT ' ' INTO TABLE DATA(lt_scopes).
READ TABLE lt_scopes TRANSPORTING NO FIELDS
WITH KEY table_line = iv_required_scope.
rv_has_scope = xsdbool( sy-subrc = 0 ).
ENDMETHOD.
METHOD check_scope.
IF has_scope(
iv_scope_string = iv_scope_string
iv_required_scope = iv_required_scope
) = abap_false.
RAISE EXCEPTION TYPE zcx_not_authorized
EXPORTING
textid = zcx_not_authorized=>missing_scope
scope = iv_required_scope.
ENDIF.
ENDMETHOD.
ENDCLASS.
" Verwendung in RAP Action
CLASS lhc_order IMPLEMENTATION.
METHOD process_order.
" JWT aus dem aktuellen Security Context
DATA(lo_auth) = NEW zcl_request_authenticator( ).
DATA(ls_jwt) = lo_auth->authenticate_request( request ).
IF ls_jwt-valid = abap_false.
" Fehler zurueckgeben
RETURN.
ENDIF.
" Scope pruefen
DATA(lo_scope) = NEW zcl_scope_authorizer( ).
TRY.
lo_scope->check_scope(
iv_scope_string = ls_jwt-jwt_payload-scope
iv_required_scope = 'order.process'
).
CATCH zcx_not_authorized.
" Keine Berechtigung
RETURN.
ENDTRY.
" Verarbeitung fortsetzen...
ENDMETHOD.
ENDCLASS.

Token Refresh

Refresh Token Flow

CLASS zcl_token_refresher DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES:
BEGIN OF ty_token_pair,
access_token TYPE string,
refresh_token TYPE string,
expires_in TYPE i,
END OF ty_token_pair.
METHODS:
refresh_access_token
IMPORTING iv_refresh_token TYPE string
RETURNING VALUE(rs_tokens) TYPE ty_token_pair
RAISING cx_web_http_client_error.
PRIVATE SECTION.
DATA ms_credentials TYPE zcl_xsuaa_config=>ty_xsuaa_credentials.
ENDCLASS.
CLASS zcl_token_refresher IMPLEMENTATION.
METHOD refresh_access_token.
DATA(lo_destination) = cl_http_destination_provider=>create_by_url(
i_url = ms_credentials-token_url
).
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = lo_destination
).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_header_field(
i_name = 'Content-Type'
i_value = 'application/x-www-form-urlencoded'
).
" Refresh Token Request
DATA(lv_body) = |grant_type=refresh_token&refresh_token={ iv_refresh_token }|.
lo_request->set_text( lv_body ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).
DATA(lv_json) = lo_response->get_text( ).
lo_client->close( ).
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = rs_tokens
).
ENDMETHOD.
ENDCLASS.

Best Practices

Do’s

EmpfehlungBegründung
Communication Arrangements nutzenAutomatisches Token-Management
Token cachenWeniger Requests an den Auth Server
Kurze Token-LifetimeMinimiert Schaden bei Token-Leak
Scopes minimal haltenPrinciple of Least Privilege
Token-Validierung auf Server-SeiteNie nur Client-seitig

Don’ts

VermeidenRisiko
Secrets im CodeSicherheitslücke
Tokens in LogsCredential Exposure
Tokens in URLsSichtbar in Browser-History
Signature nicht prüfenToken-Fälschung möglich
Expired Tokens akzeptierenReplay-Attacken

Fehlerbehandlung

Typische OAuth-Fehler

FehlerUrsacheLösung
invalid_clientFalsche Client-ID/SecretCredentials prüfen
invalid_grantAbgelaufener Refresh TokenNeuer Login erforderlich
insufficient_scopeFehlende BerechtigungenRole Collection anpassen
invalid_tokenToken manipuliert oder abgelaufenNeuen Token anfordern
" Fehlerbehandlung bei Token-Request
TRY.
DATA(lv_token) = lo_oauth_client->get_access_token( ).
CATCH cx_web_http_client_error INTO DATA(lx_http_error).
" HTTP-Fehler (Netzwerk, Timeout)
DATA(lv_msg) = lx_http_error->get_text( ).
CATCH cx_oauth_error INTO DATA(lx_oauth_error).
CASE lx_oauth_error->error_code.
WHEN 'invalid_client'.
" Client-Credentials ungueltig
WHEN 'invalid_grant'.
" Refresh Token abgelaufen
WHEN OTHERS.
" Sonstiger OAuth-Fehler
ENDCASE.
ENDTRY.

Weiterführende Themen

Zusammenfassung

OAuth 2.0 und JWT sind essentiell für sichere Cloud-Anwendungen:

  1. Client Credentials Flow für Service-zu-Service-Kommunikation ohne Benutzer
  2. Authorization Code Flow für Benutzer-basierte Authentifizierung
  3. XSUAA ist der zentrale OAuth 2.0-Server auf SAP BTP
  4. JWT-Validierung umfasst Signatur-, Ablauf-, Issuer- und Audience-Prüfung
  5. Communication Arrangements vereinfachen das Token-Management erheblich
  6. Scopes ermöglichen feingranulare Autorisierung

Nutzen Sie Communication Arrangements und Destinations für produktive Szenarien - diese übernehmen das komplette Token-Lifecycle-Management automatisch.